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.