“x는 null”과“x == null”의 차이점은 무엇입니까?


276

C # 7에서는 사용할 수 있습니다

if (x is null) return;

대신에

if (x == null) return;

기존 방식보다 새로운 방식 (이전 예)을 사용하면 어떤 이점이 있습니까?

시맨틱이 다른가?

맛의 문제 일까? 그렇지 않다면 언제 다른 것을 사용해야합니까?

참조 : C # 7.0의 새로운 기능 .


4
그것은 내가 방금보고 있던 링크이지만, 많은 정보를 제공하지 않기 때문에 OP가 질문을하는 것 같습니다. 페이지의 가장 중요한 부분은이 테스트입니다. 연산자 "is"연산자는 개체의 런타임 형식이 지정된 형식과 호환되는지 여부를 확인하는 데 사용됩니다. 다시 말해, "is"연산자를 사용하여 객체의 유형이 예상 한 것과 같은지 확인합니다. 문법을 보자 :
Simon Price

2
@SimonPrice 이것은 C #의 현재 버전에 관한 것입니다. C # 6이 질문은 패턴 일치 가있는 C # 7에 관한 것 입니다.
Patrick Hofman

@bigown 어떤 종류의 세부 사항을 찾고 있습니까?
Patrick Hofman

@PatrickHofman svick의 종류, 예를 들어 대답
Maniero

답변:


232

업데이트 : 오버로드 된 항등 연산자가 없을 때 Roslyn 컴파일러가 두 연산자의 동작을 동일하게 만들도록 업데이트되었습니다 . 참조하십시오 현재 컴파일러 결과에 코드를 ( M1그리고 M2코드에서) 그 어떠한 오버로드 같음 비교가 없을 때 어떻게되는지 보여줍니다. 둘 다 이제 성능이 더 좋습니다 ==. 오버로드 된 동등 비교기가있는 경우 코드는 여전히 다릅니다 .

이전 버전의 Roslyn 컴파일러는 아래 분석을 참조하십시오.


들어 null우리는 C #과에 사용되는 것과 차이가없는 변경할 때 6. 그러나, 일이 재미가 될 null또 다른 상수.

예를 들면 다음과 같습니다.

Test(1);

public void Test(object o)
{
    if (o is 1) Console.WriteLine("a");
    else Console.WriteLine("b");
}

테스트 결과는 다음과 같습니다 a. o == (object)1당신이 그것을 평소에 쓴 것과 비교 하면, 그것은 큰 차이를 만듭니다. is비교의 다른 측면에서 유형을 고려합니다. 그것은 멋지다!

나는 생각 == null대에 is null일정한 패턴이의 구문, '실수로'잘 알고 그냥 뭔가 is연산자와이 같은 결과 운영자 수율 같습니다.


svick이 언급 했듯이 , is nullcalls System.Object::Equals(object, object)where ==callsceq .

에 대한 IL is:

IL_0000: ldarg.1              // Load argument 1 onto the stack
IL_0001: ldnull               // Push a null reference on the stack
IL_0002: call bool [mscorlib]System.Object::Equals(object, object) // Call method indicated on the stack with arguments
IL_0007: ret                  // Return from method, possibly with a value

에 대한 IL ==:

IL_0000: ldarg.1              // Load argument 1 onto the stack
IL_0001: ldnull               // Push a null reference on the stack
IL_0002: ceq                  // Push 1 (of type int32) if value1 equals value2, else push 0
IL_0004: ret                  // Return from method, possibly with a value

우리가 이야기하고 있기 때문에 null, 이것은 인스턴스에 차이를주기 때문에 차이는 없습니다 . 항등 연산자에 과부하가 걸리면 변경 될 수 있습니다.


15
@PatrickHofman 다음과 같이 컴파일 하는 동안 is호출 처럼 보입니다 . object.Equals(x, null)==ceq그러나 당신이 말한 것처럼 결과는 동일해야합니다.
svick

16
==과부하가 걸리는 조작자 임을 항상 명심하십시오 . 원하는 동작을 가질 수 있습니다. 예를 들어, 이상하게 구현 된== 인스턴스가 실제로 null인지는 알 수 없습니다. is null반면에 실제 null 참조의 경우 항상 true를 반환합니다.) 또한 ReferenceEquals코드에있는 경우 VS 2017 전구는 (정확하게)가 is null아닌 로 변경하도록 제안합니다 == null.
nawfal

2
@PatrickHofman @svick 두 null 검사는 이제 같은 것으로 컴파일되므로 isnull 검사에 사용될 때 더 이상 함수 호출 오버 헤드가 없습니다. 증거를 위해 주석에서 @svick이 게시 한 링크를 참조하십시오.
AndreasHassing

1
@ AndreasBjørnHassingNielsen 내 답변을 업데이트했습니다.
Patrick Hofman 2016 년

2
@PatrickHofman IL이 다른 방법이되어서는 안됩니까? == System.Object :: Equals (object, object)를 호출하고 null 호출입니다 ceq
Zbigniew Ledwoń

68

과부하 등가 연산자

실제로 연산자에 null과부하가 걸린 유형과 비교할 때 두 비교 사이에는 시맨틱에 차이가 있습니다 ==. foo is null직접 참조 비교를 사용하여 결과를 결정하는 반면 foo == null, 과부하 된 ==연산자가 존재하는 경우 물론 실행 합니다.

이 예제에서는 오버로드 된 ==연산자 에 "버그"를 도입 하여 두 번째 인수가 null다음과 같은 경우 항상 예외를 발생시킵니다 .

void Main()
{
    Foo foo = null;

    if (foo is null) Console.WriteLine("foo is null"); // This condition is met
    if (foo == null) Console.WriteLine("foo == null"); // This will throw an exception
}

public class Foo
{
    public static bool operator ==(Foo foo1, Foo foo2)
    {
        if (object.Equals(foo2, null)) throw new Exception("oops");
        return object.Equals(foo1, foo2);
    }

    // ...
}

IL 코드 foo is nullceq명령어를 사용하여 직접 참조 비교를 수행합니다.

IL_0003:  ldloc.0     // foo
IL_0004:  ldnull      
IL_0005:  ceq

IL 코드 foo == null는 오버로드 된 연산자에 대한 호출을 사용합니다.

IL_0016:  ldloc.0     // foo
IL_0017:  ldnull      
IL_0018:  call        UserQuery+Foo.op_Equality

따라서 ==사용자 코드 를 사용 하면 사용자 코드가 실행 되지 않을 수 있습니다 (예기치 않은 동작 또는 성능 문제가 발생할 수 있음).

제네릭에 대한 제한

is null구문을 사용하면 형식이 참조 형식으로 제한됩니다. 컴파일러는이를 보장 is null하므로 값 유형에 사용할 수 없습니다 . 제네릭 메서드가있는 경우 is null제네릭 형식이 참조 형식으로 제한되지 않으면 사용할 수 없습니다 .

bool IsNull<T>(T item) => item is null;                  // Compile error: CS0403
bool IsNull<T>(T item) => item == null;                  // Works
bool IsNull<T>(T item) where T : class => item is null;  // Works

이것을 지적 해 주신 David Augusto Villa 에게 감사드립니다 .


2
또한 x가 제네릭 형식 인 경우 (x = null) 및 object.ReferenceEquals (x, null)가 아닌 경우 참고 (x는 null)에 클래스 제약 조건이 필요합니다.
David Augusto Villa
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.