“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 null는 ceq명령어를 사용하여 직접 참조 비교를 수행합니다.

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.