문제

기본값이 있습니까? IEqualityComparer<T> 사용하는 구현 ReferenceEquals?

EqualityComparer<T>.Default 사용하는 ObjectComparer를 사용합니다 object.Equals(). 제 경우에는 객체가 이미 구현됩니다 IEquatable<T>, 객체의 참조로만 무시하고 비교해야합니다.

도움이 되었습니까?

해결책

기본 구현이없는 경우를 대비하여 이것은 내 자신의 것입니다.

280z28에 의해 편집 : 사용에 대한 이론적 근거 RuntimeHelpers.GetHashCode(object), 많은 사람들이 아마 전에 보지 못했을 것입니다. :)이 방법에는 두 가지 효과가 있습니다. 옳은 이 구현을 요청하십시오.

  1. 객체가 null이면 0을 반환합니다. 부터 ReferenceEquals NULL 매개 변수에 대해 작동하므로 비교의 GethashCode () 구현해야합니다.
  2. 전화 Object.GetHashCode() 비정상적으로. ReferenceEquals 구체적으로 어떤 재정의를 무시합니다 Equals, gethashcode ()의 구현은 참조 equals의 효과와 일치하는 특수 메소드를 사용해야합니다. 즉, runtimehelpers.gethashcode의 정확한 것입니다.

END 280Z28

using System;
using System.Collections.Generic;
using System.Runtime.CompilerServices;

/// <summary>
/// A generic object comparerer that would only use object's reference, 
/// ignoring any <see cref="IEquatable{T}"/> or <see cref="object.Equals(object)"/>  overrides.
/// </summary>
public class ObjectReferenceEqualityComparer<T> : EqualityComparer<T>
    where T : class
{
    private static IEqualityComparer<T> _defaultComparer;

    public new static IEqualityComparer<T> Default
    {
        get { return _defaultComparer ?? (_defaultComparer = new ObjectReferenceEqualityComparer<T>()); }
    }

    #region IEqualityComparer<T> Members

    public override bool Equals(T x, T y)
    {
        return ReferenceEquals(x, y);
    }

    public override int GetHashCode(T obj)
    {
        return RuntimeHelpers.GetHashCode(obj);
    }

    #endregion
}

다른 팁

이전 답변 구현을 .net4.0+로 업데이트 할 때라고 생각했습니다. IEqualityComparer<in T> 상호 작용:

using System.Collections;
using System.Collections.Generic;
using System.Runtime.CompilerServices;

public sealed class ReferenceEqualityComparer
    : IEqualityComparer, IEqualityComparer<object>
{
    public static readonly ReferenceEqualityComparer Default
        = new ReferenceEqualityComparer(); // JIT-lazy is sufficiently lazy imo.

    private ReferenceEqualityComparer() { } // <-- A matter of opinion / style.

    public bool Equals(object x, object y)
    {
        return x == y; // This is reference equality! (See explanation below.)
    }

    public int GetHashCode(object obj)
    {
        return RuntimeHelpers.GetHashCode(obj);
    }
}

이제 각 유형마다 하나 대신 모든 참조 평등 검사에 대해 하나의 인스턴스 만 있으면됩니다. T 이전과 마찬가지로.

또한 지정할 필요가 없어 타이핑을 저장합니다 T 당신이 이것을 사용하고 싶을 때마다!


의 개념에 익숙하지 않은 사람들을 명확히하기 위해 공분산 및 비정형...

class MyClass
{
    ISet<MyClass> setOfMyClass = new HashSet<MyClass>(ReferenceEqualityComparer.Default);
}

... 잘 작동합니다. 이것은 ~ 아니다 예 : 제한 HashSet<object> 또는 유사한 (.NET4.0).


또한 이유를 궁금해하는 사람도 있습니다 x == y 참조 평등입니다 ==연산자는 정적 방법으로 컴파일 타임에 해결되며 컴파일 타임 x와 y에서 유형입니다. object 그래서 여기서 그것은 해결됩니다 ==운영자 object - 이것은 진짜 참조 평등 방법. (사실 Object.ReferenceEquals(object, object) 메소드는 단순히 객체에 대한 리디렉션입니다.)

다음은 C# 6에 대한 간단한 구현입니다.

public sealed class ReferenceEqualityComparer : IEqualityComparer, IEqualityComparer<object>
{
    public static ReferenceEqualityComparer Default { get; } = new ReferenceEqualityComparer();

    public new bool Equals(object x, object y) => ReferenceEquals(x, y);
    public int GetHashCode(object obj) => RuntimeHelpers.GetHashCode(obj);
}

편집하다 (아래 의견에 관심이 없다면이 글을 읽을 필요가 없습니다)

@Anorzaken은 많은 단락을 new 여기 수정 자. 요약합시다.

단일 정의 된 인스턴스 Equals(object,object) 방법을 구현합니다 Equals 이 유형에 대한 두 개의 선언 된 인터페이스의 방법, IEqualityComparer 그리고 일반적인 상대 IEqualityComparer<object>. 서명은 동일 하므로이 정의는 두 인터페이스를 충족시킵니다.

인스턴스 방법 ReferenceEqualityComparer.Equals(object,object) 숨을 숨 깁니다 공전 object.Equals(object,object) 방법.

없이 new 컴파일러는 이것에 대해 경고합니다. 이것이 실제로 무엇을 의미합니까?

그것은 당신이 정적을 호출하려면 object.Equals 방법, 당신은 그것을 호출 할 수 없습니다 사례ReferenceEqualityComparer. 이것은 큰 문제입니까?

아닙니다. 사실 그것은 원하는 행동입니다. 전화를 원한다면 object.Equals(a,b) 다음과 같은 코드를 통해 할 수 없습니다 ReferenceEqualityComparer.Default.Equals(a,b). 그 코드는 명확하게 요청하고 있습니다 참조 평등 - 아무도 기본/가치 평등을 수행하기를 합리적으로 기대하지 않을 것입니다. 왜 당신은 더 명확하게 코딩하지 않겠습니까? object.Equals(a,b) 그래도? 그래서 사용 new 현명하고 바람직한 행동을 제공하며 경고없이 편집 할 수 있습니다.

경고를 어떻게 억제 할 수 있습니까? 사용하는 경우 a #pragma warning disable 108/#pragma warning restore 108 그런 다음 결과는 사용과 동일합니다 new, 코드에 더 많은 소음을 추가 한 것을 제외하고. new 다른 사람들에게 더 명확하게 의도를 충분히 설명하고 설명합니다.

또는 두 인터페이스에 명시적인 구현을 사용할 수 있습니다. Equals 방법이지만 사용하는 경우 ReferenceEqualityComparer.Default.Equals(a,b) 당신은 전혀 참조 평등이 없을 것입니다.

실제로, 인스턴스 메소드로 정적 메소드를 숨기는 것은 인스턴스 지정자가 아닌 유형 지정자에서 정적 메소드를 비교하기 때문에 거의 문제가되지 않습니다. 즉, 당신은 사용합니다 Foo.StaticMethod() ~ 아니다 new Foo().StaticMethod(). 인스턴스에서 정적 메소드를 호출하는 것은 최상의 경우 불필요하고 최악의 경우 오도/부정확합니다.

또한 평등 비교를 위해서는 콘크리트 유형을 직접 사용하지 않습니다. 오히려 컬렉션과 같은 API와 함께 사용합니다.

그래서 이것은 흥미롭고 때로는 혼란스러운 토론 이었지만 다소 결실이 없었습니다.

Microsoft 제공 ObjectReferenceEqualityComparer 안에 System.Data.Entity.Infrastructure. 그냥 사용하십시오 ObjectReferenceEqualityComparer.Default 비교로.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top