C# 객체는 null은 아니지만 (myObject! = null) 여전히 false를 반환합니다.
문제
물체와 null을 비교해야합니다. 객체가 무효가되지 않으면 일부 데이터로 채 웁니다.
코드는 다음과 같습니다.
if (region != null)
{
....
}
이것은 작동하지만 언젠가 반복 및 반복 할 때 영역 객체는 NULL이 아닙니다 (디버그 모드에서 내부 데이터를 볼 수 있음). 디버깅 할 때 단계별로 IF 문 안으로 들어 가지 않습니다 ... 다음 표현식으로 빠르게 감시 할 때 : (region == null) false를 반환하고 (region! = null을 봅니다. ) 거짓도를 반환 ... 왜 그리고 어떻게?
업데이트
누군가가 대상이 ==이고! = 과부하라고 지적합니다.
public static bool operator ==(Region r1, Region r2)
{
if (object.ReferenceEquals(r1, null))
{
return false;
}
if (object.ReferenceEquals(r2, null))
{
return false;
}
return (r1.Cmr.CompareTo(r2.Cmr) == 0 && r1.Id == r2.Id);
}
public static bool operator !=(Region r1, Region r2)
{
if (object.ReferenceEquals(r1, null))
{
return false;
}
if (object.ReferenceEquals(r2, null))
{
return false;
}
return (r1.Cmr.CompareTo(r2.Cmr) != 0 || r1.Id != r2.Id);
}
해결책
== 및/또는! = 연산자가 지역 개체의 클래스에 대해 과부하되어 있습니까?
이제 과부하에 대한 코드를 게시 했으므로 다음과 같습니다.
오버로드는 아마도 다음과 같아야합니다 ( 존 스키트 그리고 필립 리크):
public static bool operator ==(Region r1, Region r2)
{
if (object.ReferenceEquals( r1, r2)) {
// handles if both are null as well as object identity
return true;
}
if ((object)r1 == null || (object)r2 == null)
{
return false;
}
return (r1.Cmr.CompareTo(r2.Cmr) == 0 && r1.Id == r2.Id);
}
public static bool operator !=(Region r1, Region r2)
{
return !(r1 == r2);
}
다른 팁
해당 연산자 과부하가 고장났습니다.
첫째, == 호출하고 결과를 반전시킴으로써! =가 구현되면 인생이 훨씬 쉬워집니다.
둘째, 무효 점검 전에 ==가 있어야합니다.
if (object.ReferenceEquals(r1, r2))
{
return true;
}
두 과부하가 모두 올바르지 않습니다
public static bool operator ==(Region r1, Region r2)
{
if (object.ReferenceEquals(r1, null))
{
return false;
}
if (object.ReferenceEquals(r2, null))
{
return false;
}
return (r1.Cmr.CompareTo(r2.Cmr) == 0 && r1.Id == r2.Id);
}
R1과 R2가 NULL 인 경우 첫 번째 테스트 (Object.Referenceequals (R1, NULL)) R2도 NULL이더라도 False를 반환합니다.
노력하다
//ifs expanded a bit for readability
public static bool operator ==(Region r1, Region r2)
{
if( (object)r1 == null && (object)r2 == null)
{
return true;
}
if( (object)r1 == null || (object)r2 == null)
{
return false;
}
//btw - a quick shortcut here is also object.ReferenceEquals(r1, r2)
return (r1.Cmr.CompareTo(r2.Cmr) == 0 && r1.Id == r2.Id);
}
동일한 데이터로 여러 스레드가 작동하는 경우 때때로 발생할 수 있습니다. 이 경우 자물쇠를 사용하여 서로를 엉망으로 만드는 것을 방지 할 수 있습니다.
"t"유형의 평등 비교를 위해이 방법을 과부하 시키십시오.
int GetHashCode() //Overrides Object.GetHashCode
bool Equals(object other) //Overrides Object.Equals; would correspond to IEquatable, if such an interface existed
bool Equals(T other) //Implements IEquatable<T>; do this for each T you want to compare to
static bool operator ==(T x, T y)
static bool operator !=(T x, T y)
유형 별 비교 코드는 한 곳에서 수행해야합니다.: 유형-안전 IEquatable<T>
인터페이스 방법 Equals(T other)
. 다른 유형 (T2)과 비교하는 경우 구현 IEquatable<T2>
또한 해당 유형의 필드 비교 코드를 Equals (T2)로 넣습니다.
모든 과부하 된 방법과 연산자는 평등 비교 작업을 기본 유형-안전 평등 (기타) 인스턴스 방법으로 전달하여 깨끗한 의존성 계층 구조가 유지되고 각 레벨에서 엄격한 보증이 도입되어 중복성과 비질의 복잡성을 제거합니다.
bool Equals(object other)
{
if (other is T) //replicate this for each IEquatable<T2>, IEquatable<T3>, etc. you may implement
return Equals( (T)other) ); //forward to IEquatable<T> implementation
return false; //other is null or cannot be compared to this instance; therefore it is not equal
}
bool Equals(T other)
{
if ((object)other == null) //cast to object for reference equality comparison, or use object.ReferenceEquals
return false;
//if ((object)other == this) //possible performance boost, ONLY if object instance is frequently compared to itself! otherwise it's just an extra useless check
//return true;
return field1.Equals( other.field1 ) &&
field2.Equals( other.field2 ); //compare type fields to determine equality
}
public static bool operator ==( T x, T y )
{
if ((object)x != null) //cast to object for reference equality comparison, or use object.ReferenceEquals
return x.Equals( y ); //forward to type-safe Equals on non-null instance x
if ((object)y != null)
return false; //x was null, y is not null
return true; //both null
}
public static bool operator !=( T x, T y )
{
if ((object)x != null)
return !x.Equals( y ); //forward to type-safe Equals on non-null instance x
if ((object)y != null)
return true; //x was null, y is not null
return false; //both null
}
논의:
이전 구현은 유형 별 (즉, 필드 평등) 비교를 중앙 집중화합니다. IEquatable<T>
유형에 대한 구현. 그만큼 ==
그리고 !=
운영자는 평행하지만 반대 구현이 있습니다. 나는 이것을 다른 하나를 참조하는 것보다 이것을 선호하여 종속적 인 하나에 대한 추가 방법 호출이 있습니다. 만약 !=
운영자는 단순히 전화를 걸 것입니다 ==
연산자는 똑같이 수행하는 연산자를 제공하는 대신 사용하는 것만으로도 사용할 수도 있습니다. !(obj1 == obj2)
추가 방법 호출을 피하십시오. 비교-스펠은 평등 연산자와 IEquatable<T>
구현은 1. 불필요한 오버 헤드 및/또는 2를 소개 할 수 있기 때문에 구현.
내가 마음에 들지 않지만 언급 해야하는 대안은이 설정을 뒤집어 평등 연산자의 유형 별 평등 코드를 중앙 집중화하고 동등한 메소드가 이에 의존하는 것입니다. 그런 다음 바로 가기를 사용할 수 있습니다 ReferenceEquals(obj1,obj2)
필립이 이전 게시물에서 언급 한 것처럼 참조 평등과 널 평등을 동시에 확인하지만 그 아이디어는 오해의 소지가 있습니다. 하나의 돌로 두 마리의 새를 죽이는 것처럼 보이지만 실제로 더 많은 작품을 만들고 있습니다. 물체를 결정한 후에는 널이나 동일한 인스턴스가 아닙니다. 또한 각 인스턴스를 확인해야합니다. NULL입니다. 내 구현에서, 당신은 단일 인스턴스가 정확히 한 번 null인지 확인합니다. Equals 인스턴스 메소드가 호출 될 때, 이미 비교되는 첫 번째 객체가 NULL이라는 것을 이미 배제했습니다. 따라서 최대 두 번의 비교 후, 우리는 어떤 방법을 사용하든 현장 점검으로 직접 이동합니다 (Equals(object),Equals(T),==,!=
). 또한, 내가 언급했듯이, 당신이 실제로 대부분의 시간을 비교하고 그 자체로 반대한다면, 현장 비교로 다이빙하기 직전에 평등 방법을 추가 할 수 있습니다. 마지막으로 추가하는 요점은 모든 레벨에서 중복/쓸모없는 점검을 도입하지 않고도 흐름/의존성 계층 구조를 유지할 수 있다는 것입니다.
여기서 이러한 수표가 옳지 않은 것입니다.
public static bool operator !=(Region r1, Region r2)
{
if (object.ReferenceEquals(r1, null))
{
return false;
}
if (object.ReferenceEquals(r2, null))
{
return false;
}
...
보고있는 매개 변수 옆에 새로 고침 아이콘을 클릭해야 할 가능성이 있습니다. vs는 모든 진술/매개 변수를 평가하지 않고 성능을 유지하려고 노력합니다. 관련이없는 장소를 변경하기 전에 확인하십시오.
bool comp;
if (object.IsNullOrEmpty(r1))
{
comp = false;
}
if (object.IsNullOrEmpty(r2))
{
comp = false;
}
return comp;