Programing

== 연산자를 재정의합니다.

lottogame 2020. 7. 2. 07:46
반응형

== 연산자를 재정의합니다. null과 비교하는 방법? [복제]


가능한 중복 :
무한 재귀없이 '=='연산자 과부하에서 null을 어떻게 확인합니까?

아마도 이것에 대한 쉬운 대답이있을 것입니다 ...하지만 나를 피하는 것 같습니다. 다음은 간단한 예입니다.

public class Person
{
   public string SocialSecurityNumber;
   public string FirstName;
   public string LastName;
}

이 특정 응용 프로그램에 대해 사회 보장 번호가 일치하고 두 이름이 일치하면 동일한 "사람"을 언급한다고 말하는 것이 타당합니다.

public override bool Equals(object Obj)
{
    Person other = (Person)Obj;
    return (this.SocialSecurityNumber == other.SocialSecurityNumber &&
        this.FirstName == other.FirstName &&
        this.LastName == other.LastName);
}

일관성을 유지하기 위해이 .Equals방법을 사용하지 않는 팀의 개발자를 위해 == 및! = 연산자도 재정의합니다 .

public static bool operator !=(Person person1, Person person2)
{
    return ! person1.Equals(person2);
}

public static bool operator ==(Person person1, Person person2)
{
    return person1.Equals(person2);
}

괜찮아요?

그러나 Person 객체가 null?

당신은 쓸 수 없습니다 :

if (person == null)
{
    //fail!
}

이로 인해 == 연산자 재정의가 실행되고 코드가 다음에서 실패합니다.

person.Equals()

null 인스턴스에서는 메서드를 호출 할 수 없으므로 메서드 호출

반면에 무한 재귀 (및 스택 오버플로 [dot com])가 발생하기 때문에 == 재정의 내부에서이 조건을 명시 적으로 확인할 수 없습니다.

public static bool operator ==(Person person1, Person person2)
{
    if (person1 == null)
    {
         //any code here never gets executed!  We first die a slow painful death.
    }
    return person1.Equals(person2);
}

그렇다면 값 평등을 위해 == 및! = 연산자를 어떻게 재정의하고 여전히 null 개체를 설명합니까?

나는 대답이 고통스럽지 않기를 바랍니다. :-)


연산자 object.ReferenceEquals(person1, null)대신 사용하십시오 ==.

public static bool operator ==(Person person1, Person person2)
{
    if (object.ReferenceEquals(person1, null))
    {
         return object.ReferenceEquals(person2, null);
    }

    return person1.Equals(person2);
}

나는 항상 이런 식으로 (== 및! = 연산자를 위해) 해왔으며 내가 만든 모든 객체에 대해이 코드를 재사용합니다.

public static bool operator ==(Person lhs, Person rhs)
{
    // If left hand side is null...
    if (System.Object.ReferenceEquals(lhs, null))
    {
        // ...and right hand side is null...
        if (System.Object.ReferenceEquals(rhs, null))
        {
            //...both are null and are Equal.
            return true;
        }

        // ...right hand side is not null, therefore not Equal.
        return false;
    }

    // Return true if the fields match:
    return lhs.Equals(rhs);
}

"! ="다음과 같이 진행됩니다.

public static bool operator !=(Person lhs, Person rhs)
{
    return !(lhs == rhs);
}

편집 여기 에서 Microsoft의 제안 된 구현과 일치
하도록 ==연산자 기능을 수정했습니다 .


당신은 항상 무시하고 넣어 수

(Object)(person1)==null

나는 이것이 확실하지 않을 것이라고 상상할 것이다.


The final (hypothetical) routine is below. It is very similar to @cdhowie's first accepted response.

public static bool operator ==(Person person1, Person person2)
{
    if (Person.ReferenceEquals(person1, person2)) return true;
    if (Person.ReferenceEquals(person1, null)) return false; //*
    return person1.Equals(person2);
}

Thanks for the great responses!

//* - .Equals() performs the null check on person2


Cast the Person instance to object:

public static bool operator ==(Person person1, Person person2)
{
    if ((object)person1 == (object)person2) return true;
    if ((object)person1 == null) return false;
    if ((object)person2 == null) return false;
    return person1.Equals(person2);
}

Overloading these operators consistently is pretty hard. My answer to a related question may serve as a template.

Basically, you first need to do a reference (object.ReferenceEquals) test to see if the object is null. Then you call Equals.


Cast the Person to an Object and then perform the comparison:

object o1 = (object)person1;
object o2 = (object)person2;
if(o1==o2) //compare instances.
   return true;
if (o1 == null || o2 == null)  //compare to null.
   return false;
//continue with Person logic.

cdhowie is on the money with the use of ReferenceEquals, but it's worth noting that you can still get an exception if someone passes null directly to Equals. Also, if you are going to override Equals it's almost always worth implementing IEquatable<T> so I would instead have.

public class Person : IEquatable<Person>
{
  /* more stuff elided */

  public bool Equals(Person other)
  {
    return !ReferenceEquals(other, null) &&
      SocialSecurityNumber == other.SocialSecurityNumber &&
      FirstName == other.FirstName &&
      LastName == other.LastName;
  }
  public override bool Equals(object obj)
  {
    return Equals(obj as Person);
  }
  public static bool operator !=(Person person1, Person person2)
  {
    return !(person1 == person2);
  }
  public static bool operator ==(Person person1, Person person2)
  {
    return ReferenceEquals(person1, person2)
      || (!ReferenceEquals(person1, null) && person1.Equals(person2));
  }
}

And of course, you should never override Equals and not override GetHashCode()

public override int GetHashCode()
{
   //I'm going to assume that different
   //people with the same SocialSecurityNumber are extremely rare,
   //as optimise by hashing on that alone. If this isn't the case, change this
   return SocialSecurityNumber.GetHashCode();
}

It's also worth noting that identity entails equality (that is, for any valid concept of "equality" something is always equal to itself). Since equality tests can be expensive and occur in loops, and since comparing something with itself tends to be quite common in real code (esp. if objects are passed around in several places), it can be worth adding as a shortcut:

  public bool Equals(Person other)
  {
    return !ReferenceEquals(other, null) &&
      ReferenceEquals(this, other) ||
      (
        SocialSecurityNumber == other.SocialSecurityNumber &&
        FirstName == other.FirstName &&
        LastName == other.LastName
      );
  }

Just how much of a benefit short-cutting on ReferenceEquals(this, other) is can vary considerably depending on the nature of the class, but whether it is worth while doing or not is something one should always consider, so I include the technique here.


Easier than any of those approaches would be to just use

public static bool operator ==(Person person1, Person person2)   
{   
    EqualityComparer<Person>.Default.Equals(person1, person2)
} 

This has the same null equality semantics as the approaches that everyone else is proposing, but it's the framework's problem to figure out the details :)

참고URL : https://stackoverflow.com/questions/4219261/overriding-operator-how-to-compare-to-null

반응형