C # : 'is'키워드 및 Not 검사


287

이것은 어리석은 질문이지만이 코드를 사용하여 무언가가 특정 유형인지 확인할 수 있습니다 ...

if (child is IContainer) { //....

"NOT"인스턴스를 확인하는 더 우아한 방법이 있습니까?

if (!(child is IContainer)) { //A little ugly... silly, yes I know...

//these don't work :)
if (child !is IContainer) {
if (child isnt IContainer) { 
if (child aint IContainer) { 
if (child isnotafreaking IContainer) { 

예, 그렇습니다 ... 바보 같은 질문 ...

코드가 어떻게 생겼는지에 대한 의문이 있기 때문에 메소드 시작시 간단히 리턴됩니다.

public void Update(DocumentPart part) {
    part.Update();
    if (!(DocumentPart is IContainer)) { return; }
    foreach(DocumentPart child in ((IContainer)part).Children) {
       //...etc...

105
나는 개인적으로 "어린이 isotafreaking ..."을 좋아합니다. 이 키워드를 C # 5
— Joseph

이 상황을 알고 싶은데? 이 코드의 "다른"부분은 어떻게 생겼으며 테스트를 거꾸로 할 수 없습니까? 코드에서 "자식이 IContainer가 아닌 경우 예외를 던지십시오"또는 "자식이 IContainer가 아닌 경우 IFoo 일 수 있으므로 다음에 시도하겠습니다"라고 말한 경우 거기에 다른 진술이 포함되어 있지 않습니까? 아마도 뭔가 빠졌을 것입니다.
— 마틴 펙

1
@MartinPeck, else 절이 없을 수 있습니다. 그것이 내가 이것을 찾은 이유입니다.
— Joshua Walsh

@MartinPeck 샘플 if (!(argument is MapsControlViewModel vm)) { return; }은 다음과 같습니다. 훨씬 덜 읽을 수 있습니다.
— ANeves

어쩌면 우리가 일반적으로 필요하다 ifnot문
— 데이브 Cousineau

답변:


301
if(!(child is IContainer))

갈 유일한 연산자입니다 ( IsNot연산자 가 없습니다 ).

이를 수행하는 확장 메소드를 빌드 할 수 있습니다.

public static bool IsA<T>(this object obj) {
    return obj is T;
}

그리고 그것을 사용하여 :

if (!child.IsA<IContainer>())

그리고 당신은 당신의 주제를 따를 수 있습니다 :

public static bool IsNotAFreaking<T>(this object obj) {
    return !(obj is T);
}

if (child.IsNotAFreaking<IContainer>()) { // ...

업데이트 (OP의 코드 스 니펫 고려) :

나중에 값을 실제로 캐스팅하기 때문에 as대신 사용할 수 있습니다 .

public void Update(DocumentPart part) {
    part.Update();
    IContainer containerPart = part as IContainer;
    if(containerPart == null) return;
    foreach(DocumentPart child in containerPart.Children) { // omit the cast.
       //...etc...

1
ck : 나는 운영자의 의미에서 아무 의미가 없습니다 IsNot.
— Mehrdad Afshari

5
예. 분명하지 않은 경우 농담입니다.
— Mehrdad Afshari 2016 년

111

이 방법으로 할 수 있습니다 :

object a = new StreamWriter("c:\\temp\\test.txt");

if (a is TextReader == false)
{
   Console.WriteLine("failed");
}

2
@Frank-yep, is 키워드는 boolean을 제공합니다. false와 비교할 수 있습니다
— cjk

32
@Frank에 is비해 우선 순위가 높기 때문에 작동 합니다 ==. 사용할 수없는 유일한 이유 !x is f는 이보다 우선 순위가 낮기 때문 !입니다.
— Mehrdad Afshari

나는 이것을 좋아하지만 변수를 소개 할 때 제대로 작동하지 않는 것 같습니다. if (a is TextReader reader == false)"작동해야합니다."그러나 변수가 초기화되지 않았 음을 나타내는 실제 경로에서 변수를 사용할 수 없습니다.
— Dave Cousineau

@DaveCousineau-일반적으로 도입 된 변수를 사용하려고 할 때 변수를 타입 검사하고 도입합니다. 내가하지 확인 유형 체킹이 실패한 경우 변수가 유용 할 것이다 어떻게 해요 (면책 조항 - 나는 "패턴 일치"기능을 찾을 모두 가난의 이름과 사용으로 코드 냄새의 나쁜있다. out매개 변수)
— StingyJack

@StingyJack은 실제 경로 에서 변수가 초기화되지 않은 것으로 간주 되는 일종의 결함이 있습니다. if (a is TextReader reader == true)변수가 초기화되지 않았다고 생각 하더라도 .
— Dave Cousineau

11

왜 다른 것을 사용하지 않습니까?

if (child is IContainer)
{
  //
}
else
{
  // Do what you want here
}

친숙하고 간단합니다.


3
아무 문제가 없습니다-이것은 단지 nitpick 질문입니다. 특정 유형이 아닌 경우 즉시 함수를 종료하고 싶었습니다. 나는 영원히 그것을 했어 (! (child is Something)), 그러나 나는 더 좋은 방법이 없다는 것을 확신 할 것이라고 생각했다.
— Hugoware

1
문제의 샘플 코드에서 빈 대괄호를 의미합니다. 현명한 대안처럼 들리지 않습니다.
— ANeves

9

올바른 방법 이지만 "NOT"인스턴스를 확인하는보다 우아한 방법을 만들기 위해 확장 방법 세트를 작성할 수 있습니다.

public static bool Is<T>(this object myObject)
{
    return (myObject is T);
}

public static bool IsNot<T>(this object myObject)
{
    return !(myObject is T);
}

그럼 당신은 쓸 수 있습니다 :

if (child.IsNot<IContainer>())
{
    // child is not an IContainer
}

7

아직 언급되지 않았습니다. 작동하고 사용하는 것보다 낫다고 생각합니다.!(child is IContainer)

if (part is IContainer is false)
{
    return;
}

is구문 : expr is constant , 여기서 expr은 평가할 표현식이고 constant는 테스트 할 값입니다.


3
마찬가지로 당신도 할 수 if (part as IContainer is null)있습니다. 솔직히 어느 쪽이 더 좋은지 잘 모르겠습니다.
— Flynn1179

5

추한? 동의하지 않습니다. 유일한 다른 방법 (개인적으로 이것이 "더 추악하다고 생각합니다") :

var obj = child as IContainer;
if(obj == null)
{
   //child "aint" IContainer
}

@Mehrdad-Nullable? 이것이 사용되지 않아야 작동합니다. 그것은 더 못생긴 방법의 예일뿐입니다.
— stevehipwell

@ Steveo3000 : 예,하지만 명시 적으로 언급해야합니까? 는 IS as절. obj as int항상 컴파일 시간 오류입니다.
— Mehrdad Afshari

@Mehrdad-동의 함, BFree는이를 반영하기 위해 자신의 게시물을 편집 할 수 있습니다. 우리에게 'obj as int?'
— stevehipwell

@ Stevo3000 : 그러나 아무것도 잘못 생각하지 않습니다. IContainer는 값 유형이 아닌 인터페이스처럼 느껴집니다. 가치 유형에주의를 기울여야하며 항상 is형태 의 직접 번역이 아니라는 점을 지적하고 싶었습니다 .
— Mehrdad Afshari

값 유형과 참조 유형을 처리하는 if (obj == default (IContainer))를 선택적으로 수행 할 수 있습니다.
— Joseph

3

is당신은 아무것도 할 수 있도록 부울 결과에 운영자 평가하여, 당신은 그렇지 않으면 부울에 할 수있을 것입니다. 부정하려면 !연산자를 사용하십시오 . 이것을 위해 왜 다른 연산자를 원하십니까?


5
다른 연산자가 아닙니다. 여분의 parens을 떨어 뜨릴 수있는 키워드가 있는지 궁금합니다. 중요한 픽픽이지만 궁금했습니다.
— Hugoware

알았어요 귀하의 예에서 나는 당신이 새로운 전담 운영자를 찾고 있다는 인상을 받았습니다.
— Brian Rasmussen

그런 특수 연산자를 갖는 것은 좋지 않습니다. 왜냐하면 우리는 이런 식으로 할 것이기 때문입니다.
— BuddhiP

3

확장 방법 IsNot<T>은 구문을 확장하는 좋은 방법입니다. 명심하십시오

var container = child as IContainer;
if(container != null)
{
  // do something w/ contianer
}

같은 일을하는 것보다 더 나은 성능

if(child is IContainer)
{
  var container = child as IContainer;
  // do something w/ container
}

귀하의 경우 메소드에서 돌아올 때 중요하지 않습니다. 즉, 유형 확인 후 즉시 유형 변환을 수행하지 않도록주의하십시오.


3

이것은 괄호 문제를 피할 수는 없지만 Google을 통해 여기에 오는 사람들을 위해 코드의 나머지 부분을 좀 더 깨끗하게하기 위해 새로운 구문 (C # 7 현재)이 있다고 언급해야합니다.

if (!(DocumentPart is IContainer container)) { return; }
foreach(DocumentPart child in container.Children) {
    ...

이렇게하면 이중 캐스트, 널 검사 및 널이 될 수있는 범위에서 변수를 사용할 수 없습니다.


2

IS 연산자가 일반적으로 가장 좋은 방법이지만 일부 환경에서 사용할 수있는 대안이 있습니다. as 연산자를 사용하고 null을 테스트 할 수 있습니다.

MyClass mc = foo as MyClass;
if ( mc == null ) { }
else {}

2

C # 9 논리 패턴을 포함 할 것이다 (.NET 5 출시 예정) and, or그리고 not우리가 더 우아하게이 쓸 수있는 :

if (child is not IContainer) { ... }

마찬가지로이 패턴을 사용하여 null을 확인할 수 있습니다.

if (child is not null) { ... }

이 변경 사항을 추적 하는 Github 문제 에 대한 자세한 내용을 찾을 수 있습니다 .


당사 사이트를 사용함과 동시에 당사의 쿠키 정책과 개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.