무한 재귀 없이 '==' 연산자 오버로드에서 null을 어떻게 확인합니까?

StackOverflow https://stackoverflow.com/questions/73713

  •  09-06-2019
  •  | 
  •  

문제

다음은 == 연산자 오버로드 메서드에서 무한 재귀를 발생시킵니다.

    Foo foo1 = null;
    Foo foo2 = new Foo();
    Assert.IsFalse(foo1 == foo2);

    public static bool operator ==(Foo foo1, Foo foo2) {
        if (foo1 == null) return foo2 == null;
        return foo1.Equals(foo2);
    }

Null을 어떻게 확인하나요?

도움이 되었습니까?

해결책

사용 ReferenceEquals:

Foo foo1 = null;
Foo foo2 = new Foo();
Assert.IsFalse(foo1 == foo2);

public static bool operator ==(Foo foo1, Foo foo2) {
    if (object.ReferenceEquals(null, foo1))
        return object.ReferenceEquals(null, foo2);
    return foo1.Equals(foo2);
}

다른 팁

오버로드 메소드에서 객체로 캐스트:

public static bool operator ==(Foo foo1, Foo foo2) {
    if ((object) foo1 == null) return (object) foo2 == null;
    return foo1.Equals(foo2);
}

사용 참조Equals.로부터 MSDN 포럼:

public static bool operator ==(Foo foo1, Foo foo2) {
    if (ReferenceEquals(foo1, null)) return ReferenceEquals(foo2, null);
    if (ReferenceEquals(foo2, null)) return false;
    return foo1.field1 == foo2.field2;
}

노력하다 Object.ReferenceEquals(foo1, null)

어쨌든, 나는 과부하를 권장하지 않습니다 ==운영자;참조를 비교하는 데 사용해야 하며, Equals "의미론적" 비교를 위해.

내가 재정의한 경우 bool Equals(object obj) 그리고 나는 교환원을 원해요 == 그리고 Foo.Equals(object obj) 동일한 답변을 반환하려면 일반적으로 다음을 구현합니다. != 연산자는 다음과 같습니다:

public static bool operator ==(Foo foo1, Foo foo2) {
  return object.Equals(foo1, foo2);
}
public static bool operator !=(Foo foo1, Foo foo2) {
  return !object.Equals(foo1, foo2);
}

운영자 == 그런 다음 나를 위해 모든 null 검사를 수행한 후 결국 전화를 걸게 됩니다. foo1.Equals(foo2) 두 개가 동일한지 실제 확인을 수행하도록 재정의했습니다.

C# 7 이상을 사용하는 경우 null 상수 패턴 일치를 사용할 수 있습니다.

public static bool operator==(Foo foo1, Foo foo2)
{
    if (foo1 is null)
        return foo2 is null;
    return foo1.Equals(foo2);
}

이렇게 하면 object.ReferenceEquals(foo1, null)을 호출하는 것보다 약간 더 깔끔한 코드가 제공됩니다.

내 접근 방식은 다음과 같습니다

(object)item == null

내가 의지하고 있는 것 object잘못될 수 없는 자신의 항등 연산자입니다.또는 사용자 정의 확장 방법(및 오버로드):

public static bool IsNull<T>(this T obj) where T : class
{
    return (object)obj == null;
}

public static bool IsNull<T>(this T? obj) where T : struct
{
    return !obj.HasValue;
}

또는 더 많은 사례를 처리하기 위해 다음과 같이 할 수 있습니다.

public static bool IsNull<T>(this T obj) where T : class
{
    return (object)obj == null || obj == DBNull.Value;
}

제약으로 인해 IsNull 값 유형에 대해.이제 전화하는 것만큼 달콤해

object obj = new object();
Guid? guid = null; 
bool b = obj.IsNull(); // false
b = guid.IsNull(); // true
2.IsNull(); // error

이는 전체적으로 null을 확인하는 일관되고 오류가 발생하지 않는 스타일을 가지고 있음을 의미합니다.나도 찾았어 (object)item == null 것보다 아주 아주 아주 조금 더 빠릅니다. Object.ReferenceEquals(item, null), 하지만 중요한 경우에만 가능합니다(현재 모든 것을 미세하게 최적화해야 하는 작업을 진행 중입니다!).

동등성 검사 구현에 대한 전체 가이드를 보려면 다음을 참조하세요. 참조 유형의 두 인스턴스를 비교하는 "모범 사례"는 무엇입니까?

정적 Equals(Object, Object) 방법 두 개체가 있는지 여부를 나타냅니다. objA 그리고 objB, 같다.또한 값이 다음과 같은 개체를 테스트할 수도 있습니다. null 평등을 위해.비교한다 objA 그리고 objB 평등을 위해 다음과 같이 :

  • 두 개체가 동일한 개체 참조를 나타내는지 여부를 확인합니다.그렇다면 메서드는 다음을 반환합니다. true.이 테스트는 ReferenceEquals 방법.게다가 둘 다라면 objA 그리고 objB ~이다 null, 메서드가 반환됩니다. true.
  • 다음 중 하나를 결정합니다. objA 또는 objB ~이다 null.그렇다면 반환됩니다. false.두 객체가 동일한 객체 참조를 나타내지 않고 둘 다 동일하지 않은 경우 null, 그것은 전화한다 objA.Equals(objB) 결과를 반환합니다.이는 다음을 의미합니다. objA 재정의 Object.Equals(Object) 메서드에서 이 재정의가 호출됩니다.

.

public static bool operator ==(Foo objA, Foo objB) {
    return Object.Equals(objA, objB);
}

추가 답변 연산자를 재정의하여 null과 비교하는 방법 여기에 중복으로 리디렉션됩니다.

값 개체를 지원하기 위해 이 작업을 수행하는 경우 새 표기법이 편리하다고 생각하며 비교가 수행되는 위치가 하나만 있는지 확인하고 싶습니다.또한 Object.Equals(A, B)를 활용하면 null 검사가 단순화됩니다.

그러면 ==, !=, Equals 및 GetHashCode가 오버로드됩니다.

    public static bool operator !=(ValueObject self, ValueObject other) => !Equals(self, other);
    public static bool operator ==(ValueObject self, ValueObject other) => Equals(self, other);
    public override bool Equals(object other) => Equals(other as ValueObject );
    public bool Equals(ValueObject other) {
        return !(other is null) && 
               // Value comparisons
               _value == other._value;
    }
    public override int GetHashCode() => _value.GetHashCode();

더 복잡한 객체의 경우 Equals 및 더 풍부한 GetHashCode에 추가 비교를 추가하세요.

실제로 확인하는 더 간단한 방법이 있습니다. null 이 경우:

if (foo is null)

그게 다야!

이 기능은 C# 7에서 도입되었습니다.

연산자 ==의 오버로드에서 흔히 발생하는 오류는 다음을 사용하는 것입니다. (a == b), (a ==null), 또는 (b == null) 참조 동등성을 확인합니다.대신에 이것은 결과 오버로드된 연산자 ==에 대한 호출로 인해 infinite loop.사용 ReferenceEquals 또는 루프를 피하기 위해 유형을 물체에 캐스트합니다.

이것을 확인해 보세요

// If both are null, or both are same instance, return true.
if (System.Object.ReferenceEquals(a, b))// using ReferenceEquals
{
    return true;
}

// If one is null, but not both, return false.
if (((object)a == null) || ((object)b == null))// using casting the type to Object
{
    return false;
}

참조 Equals() 및 연산자 == 오버로드에 대한 지침

개체 속성을 사용하고 결과 NullReferenceException을 포착할 수 있습니다.시도하는 속성이 Object에서 상속되거나 재정의된 경우 이는 모든 클래스에서 작동합니다.

public static bool operator ==(Foo foo1, Foo foo2)
{
    //  check if the left parameter is null
    bool LeftNull = false;
    try { Type temp = a_left.GetType(); }
    catch { LeftNull = true; }

    //  check if the right parameter is null
    bool RightNull = false;
    try { Type temp = a_right.GetType(); }
    catch { RightNull = true; }

    //  null checking results
    if (LeftNull && RightNull) return true;
    else if (LeftNull || RightNull) return false;
    else return foo1.field1 == foo2.field2;
}
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top