IEqualityComparer에서 델리게이트 랩


127

여러 Linq.Enumerable 함수는 IEqualityComparer<T>. delegate(T,T)=>bool구현하기에 적합한 편리한 래퍼 클래스가 IEqualityComparer<T>있습니까? 하나를 작성하는 것은 쉽지만 (올바른 해시 코드를 정의하는 데 문제가있는 경우) 즉시 사용할 수있는 솔루션이 있는지 알고 싶습니다.

특히, 작업을 설정하고 싶습니다. Dictionary 키만 사용하여 멤버십을 정의하고 (다른 규칙에 따라 값을 유지함) .

답변:


44

일반적으로 @Sam에 대한 답변에 댓글을 달아서이 문제를 해결했습니다 (원래 게시물을 수정하여 동작을 변경하지 않고 조금 정리했습니다).

다음은 기본 해싱 정책에 대한 [IMNSHO] 중요 수정과 함께 @ Sam 's answer의 리프입니다 :-

class FuncEqualityComparer<T> : IEqualityComparer<T>
{
    readonly Func<T, T, bool> _comparer;
    readonly Func<T, int> _hash;

    public FuncEqualityComparer( Func<T, T, bool> comparer )
        : this( comparer, t => 0 ) // NB Cannot assume anything about how e.g., t.GetHashCode() interacts with the comparer's behavior
    {
    }

    public FuncEqualityComparer( Func<T, T, bool> comparer, Func<T, int> hash )
    {
        _comparer = comparer;
        _hash = hash;
    }

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

    public int GetHashCode( T obj )
    {
        return _hash( obj );
    }
}

5
내가 아는 한 이것은이다 올바른 대답은. 모든 IEqualityComparer<T>잎 것을 GetHashCode알아 단지 스트레이트 헤어 졌있다.
Dan Tao

1
@Joshua Frank : 해시 평등을 사용하여 평등을 암시하는 것은 유효하지 않습니다. 반대의 경우에만 적용됩니다. 요컨대 @Dan Tao는 자신이 말한 내용이 완전히 정확하며,이 답변은 단순히이 사실을 이전에 불완전한 답변에 적용한 것입니다
Ruben Bartelink

2
@Ruben Bartelink : 설명해 주셔서 감사합니다. 그러나 나는 여전히 t => 0의 해싱 정책을 이해하지 못합니다. 모든 객체가 항상 같은 것으로 해시되면 ( @) Dan Tao의 요점에 따라 obj.GetHashCode를 사용 하는 것 보다 더 손상 되지 않습니까? 호출자가 항상 좋은 해시 함수를 제공하도록 강제하지 않는 이유는 무엇입니까?
Joshua Frank

1
따라서 Func에있는 임의의 알고리즘이 제공되어 해시 코드가 다르더라도 true를 반환 할 수 없다고 가정하는 것은 합리적이지 않습니다. 항상 0을 돌려주는 것이 해싱이 아니라는 요점은 사실입니다. 그렇기 때문에 프로파일 러가 검색이 효율적이지 않다고 말할 때 해싱 Func을 사용하는 과부하가 발생하는 이유입니다. 이 모든 것의 유일한 요점은 기본 해싱 알고리즘을 사용하려면 100 % 작동하고 위험한 표면적으로 올바른 행동을하지 않아야한다는 것입니다. 그리고 우리는 공연을 할 수 있습니다!
Ruben Bartelink

4
즉, 사용자 정의 비교기를 사용 하므로 기본 비교기 와 관련된 객체의 기본 해시 코드와 는 아무런 관련이 없으므로 사용할 수 없습니다.
피트 브리츠

170

의 중요성에 GetHashCode

다른 사용자들은 이미 모든 사용자 정의 IEqualityComparer<T>구현 이 실제로 GetHashCode메소드를 포함해야 한다는 사실에 대해 언급했습니다 . 그러나 아무도 상세하게 설명 할 필요가 없습니다.

이유는 다음과 같습니다. 귀하의 질문은 특히 LINQ 확장 방법을 언급합니다. 거의 모든 이들은 효율성을 위해 내부적으로 해시 테이블을 사용하기 때문에, 제대로 작동하려면 해시 코드에 의존하고 있습니다.

가지고 Distinct예를 들어. 이 확장 방법이 사용 된 Equals방법 중 하나라면이 확장 방법의 의미를 고려하십시오 . 가지고있는 항목이 이미 순서대로 스캔되었는지 어떻게 알 수 Equals있습니까? 이미 살펴본 전체 값 모음을 열거하고 일치하는지 확인합니다. 이것은 DistinctO (N ) 대신 최악의 O (N 2 ) 알고리즘을 사용하게됩니다!

다행히도 그렇지 않습니다. Distinct하지 사용 Equals; 또한 사용 GetHashCode합니다. 사실, 그것은 절대적으로 하지 않습니다 없이 제대로 작동 IEqualityComparer<T>적절한를 공급하는GetHashCode . 아래는이를 설명하는 좋은 예입니다.

다음 유형이 있다고 가정하십시오.

class Value
{
    public string Name { get; private set; }
    public int Number { get; private set; }

    public Value(string name, int number)
    {
        Name = name;
        Number = number;
    }

    public override string ToString()
    {
        return string.Format("{0}: {1}", Name, Number);
    }
}

이제 내가 List<Value>있고 다른 이름을 가진 모든 요소를 ​​찾고 싶다고 말하십시오 . 이것은 Distinct커스텀 평등 비교기 를 사용하기 위한 완벽한 유스 케이스입니다 . Aku의 답변Comparer<T> 에서 클래스를 사용하십시오 .

var comparer = new Comparer<Value>((x, y) => x.Name == y.Name);

이제 Value같은 Name속성을 가진 많은 요소가 있다면 모두에서 반환 된 하나의 값으로 축소되어야 Distinct합니까? 보자 ...

var values = new List<Value>();

var random = new Random();
for (int i = 0; i < 10; ++i)
{
    values.Add("x", random.Next());
}

var distinct = values.Distinct(comparer);

foreach (Value x in distinct)
{
    Console.WriteLine(x);
}

산출:

x : 1346013431
x : 1388845717
x : 1576754134
x : 1104067189
x : 1144789201
x : 1862076501
x : 1573781440
x : 646797592
x : 655632802
x : 1206819377

흠, 그것은 작동하지 않았다?

무엇에 대해 GroupBy? 시도해 봅시다 :

var grouped = values.GroupBy(x => x, comparer);

foreach (IGrouping<Value> g in grouped)
{
    Console.WriteLine("[KEY: '{0}']", g);
    foreach (Value x in g)
    {
        Console.WriteLine(x);
    }
}

산출:

[KEY = 'x : 1346013431']
x : 1346013431
[KEY = 'x : 1388845717']
x : 1388845717
[KEY = 'x : 1576754134']
x : 1576754134
[KEY = 'x : 1104067189']
x : 1104067189
[KEY = 'x : 1144789201']
x : 1144789201
[KEY = 'x : 1862076501']
x : 1862076501
[KEY = 'x : 1573781440']
x : 1573781440
[KEY = 'x : 646797592']
x : 646797592
[KEY = 'x : 655632802']
x : 655632802
[KEY = 'x : 1206819377']
x : 1206819377

다시 : 작동하지 않았다.

당신이 그것에 대해 생각한다면, 내부적 Distinct으로 HashSet<T>(또는 동등한) GroupBy것을 사용하고 Dictionary<TKey, List<T>>내부 와 같은 것을 사용하는 것이 합리적입니다 . 왜 이러한 방법이 작동하지 않는지 설명 할 수 있습니까? 이것을 시도하자 :

var uniqueValues = new HashSet<Value>(values, comparer);

foreach (Value x in uniqueValues)
{
    Console.WriteLine(x);
}

산출:

x : 1346013431
x : 1388845717
x : 1576754134
x : 1104067189
x : 1144789201
x : 1862076501
x : 1573781440
x : 646797592
x : 655632802
x : 1206819377

그래 ... 이해하기 시작 했어?

이 예제 GetHashCode에서 IEqualityComparer<T>구현에 적절한 것을 포함시키는 것이 왜 중요한지 분명히 알 수 있습니다.


원래 답변

orip의 답변 확대 :

여기에는 몇 가지 개선 사항이 있습니다.

  1. 먼저, Func<T, TKey>대신에 Func<T, object>; 이렇게하면 실제 keyExtractor자체 에 값 유형 키가 박싱되지 않습니다.
  2. 둘째, 실제로 where TKey : IEquatable<TKey>제약 조건을 추가합니다 . 이것은 Equals호출 에서 권투를 막을 것입니다 ( 매개 변수를 object.Equals취하십시오 object; 그것을 권투하지 않고 매개 변수 IEquatable<TKey>를 취 하려면 구현 이 필요 TKey합니다). 분명히 이것은 너무 엄격한 제한을 가할 수 있으므로 제약없이 기본 클래스를 만들고 파생 클래스를 만들 수 있습니다.

결과 코드는 다음과 같습니다.

public class KeyEqualityComparer<T, TKey> : IEqualityComparer<T>
{
    protected readonly Func<T, TKey> keyExtractor;

    public KeyEqualityComparer(Func<T, TKey> keyExtractor)
    {
        this.keyExtractor = keyExtractor;
    }

    public virtual bool Equals(T x, T y)
    {
        return this.keyExtractor(x).Equals(this.keyExtractor(y));
    }

    public int GetHashCode(T obj)
    {
        return this.keyExtractor(obj).GetHashCode();
    }
}

public class StrictKeyEqualityComparer<T, TKey> : KeyEqualityComparer<T, TKey>
    where TKey : IEquatable<TKey>
{
    public StrictKeyEqualityComparer(Func<T, TKey> keyExtractor)
        : base(keyExtractor)
    { }

    public override bool Equals(T x, T y)
    {
        // This will use the overload that accepts a TKey parameter
        // instead of an object parameter.
        return this.keyExtractor(x).Equals(this.keyExtractor(y));
    }
}

1
귀하의 StrictKeyEqualityComparer.Equals방법은와 같습니다 KeyEqualityComparer.Equals. 합니까 TKey : IEquatable<TKey>제약 메이크업의 TKey.Equals작업은 다르게?
저스틴 모건

2
@JustinMorgan : 그렇습니다. 첫 번째 경우, TKey임의의 유형일 수 있기 때문에 컴파일러는 가상적인 방법 Object.Equals을 사용합니다 int. 이후 후자의 경우, 그러나, TKey구현하기 위해 구속 IEquatable<TKey>TKey.Equals방법은 어떤 권투를 필요로하지 것이다 사용됩니다.
Dan Tao

2
정보에 감사드립니다. GetHashCode가 이러한 답변을 볼 때까지 이러한 LINQ 의미를 알지 못했습니다. 나중에 사용하기 위해 알기에 좋습니다.
저스틴 모건

1
@JohannesH : 아마! 필요를 없 Would을 것 StringKeyEqualityComparer<T, TKey>입니다.
Dan Tao

1
+1 @DanTao : .Net에서 동등성을 정의 할 때 해시 코드를 무시해서는 안되는 이유에 대해 설명해 주셔서 감사합니다.
Marcelo Cantos 2016 년

118

등식 검사를 사용자 정의하려는 경우 비교 자체가 아니라 비교할 키를 정의하는 데 99 %의 시간이 소요됩니다.

이것은 우아한 솔루션 일 수 있습니다 (Python의 목록 정렬 방법 의 개념 ).

용법:

var foo = new List<string> { "abc", "de", "DE" };

// case-insensitive distinct
var distinct = foo.Distinct(new KeyEqualityComparer<string>( x => x.ToLower() ) );

KeyEqualityComparer클래스 :

public class KeyEqualityComparer<T> : IEqualityComparer<T>
{
    private readonly Func<T, object> keyExtractor;

    public KeyEqualityComparer(Func<T,object> keyExtractor)
    {
        this.keyExtractor = keyExtractor;
    }

    public bool Equals(T x, T y)
    {
        return this.keyExtractor(x).Equals(this.keyExtractor(y));
    }

    public int GetHashCode(T obj)
    {
        return this.keyExtractor(obj).GetHashCode();
    }
}

3
이것은 aku의 대답보다 훨씬 낫습니다.
SLaks

확실히 올바른 접근 방식. 내 의견으로는 언급 할 수있는 몇 가지 개선 사항이 있습니다.
Dan Tao

1
이것은 매우 우아한 코드이지만 질문에 대답하지 않으므로 @aku의 대답을 대신 수락했습니다. Func <T, T, bool>에 대한 래퍼를 원했고 키가 이미 사전에서 분리되어 있기 때문에 키를 추출 할 필요가 없습니다.
Marcelo Cantos

6
@Marcelo : 괜찮습니다. 그렇게 할 수 있습니다. 그러나 @aku의 접근 방식을 취하려면 실제로 Ruben의 답변 에서 제안 된 것처럼 값에 Func<T, int>해시 코드를 제공 하기 위해 a 를 추가 해야 합니다 . 그렇지 않으면 , 특히 LINQ 확장 메서드에서의 유용성과 관련하여 남아 있는 구현이 상당히 손상 되었습니다. 이것이 왜 그런지에 대한 토론은 내 대답을 참조하십시오. TIEqualityComparer<T>
Dan Tao

이것은 좋지만 선택한 키가 값 유형 인 경우 불필요한 복싱이 필요합니다. 아마도 키를 정의하기 위해 TKey를 사용하는 것이 좋습니다.
그레이엄 암브로스

48

포장 상자에 래퍼가없는 것이 두렵습니다. 그러나 하나를 만드는 것은 어렵지 않습니다.

class Comparer<T>: IEqualityComparer<T>
{
    private readonly Func<T, T, bool> _comparer;

    public Comparer(Func<T, T, bool> comparer)
    {
        if (comparer == null)
            throw new ArgumentNullException("comparer");

        _comparer = comparer;
    }

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

    public int GetHashCode(T obj)
    {
        return obj.ToString().ToLower().GetHashCode();
    }
}

...

Func<int, int, bool> f = (x, y) => x == y;
var comparer = new Comparer<int>(f);
Console.WriteLine(comparer.Equals(1, 1));
Console.WriteLine(comparer.Equals(1, 2));

1
그러나 GetHashCode 구현에주의하십시오. 실제로 해시 테이블에서 사용하려는 경우 좀 더 견고한 것을 원할 것입니다.
thecoop

46
이 코드에는 심각한 문제가 있습니다! 이 비교 자와 관련하여 동일하지만 해시 코드가 다른 두 개의 객체를 가진 클래스를 쉽게 만들 수 있습니다.
empi

10
이를 해결하려면 클래스 private readonly Func<T, int> _hashCodeResolver에는 생성자에 전달되어 GetHashCode(...)메소드에 사용되어야하는 다른 멤버 가 필요 합니다 .
herzmeister

6
궁금합니다 : 왜 obj.ToString().ToLower().GetHashCode()대신에 사용 하고 obj.GetHashCode()있습니까?
저스틴 모건

3
이 구현에서는 프레임 워크에서 IEqualityComparer<T>항상 배후에서 해싱을 사용하는 (예 : LINQ의 GroupBy, Distinct, Except, Join 등) 해시와 관련된 MS 계약이 중단됩니다. MS의 문서 발췌문은 다음과 같습니다. "두 객체 x와 y에 대해 Equals 메서드가 true를 반환하면 x에 대한 GetHashCode 메서드가 반환 한 값이 y에 대해 반환 된 값과 같아야합니다." 참조 : msdn.microsoft.com/ko-kr/library/ms132155
devgeezer

22

Dan Tao의 답변과 동일하지만 몇 가지 개선 사항이 있습니다.

  1. 에 의존는 EqualityComparer<>.Default이 값 유형 (대한 복싱 피할 수 있도록 비교 실제 작업을 수행하기 위해 struct시행하고 있습니다들) IEquatable<>.

  2. 때문에 EqualityComparer<>.Default사용이 폭발하지 않습니다 null.Equals(something).

  3. 비교기 IEqualityComparer<>의 인스턴스를 작성하는 정적 메소드가있는 정적 랩퍼를 제공 하여 호출을 용이하게합니다. 비교

    Equality<Person>.CreateComparer(p => p.ID);

    new EqualityComparer<Person, int>(p => p.ID);
  4. IEqualityComparer<>키 에 지정할 과부하를 추가했습니다 .

클래스:

public static class Equality<T>
{
    public static IEqualityComparer<T> CreateComparer<V>(Func<T, V> keySelector)
    {
        return CreateComparer(keySelector, null);
    }

    public static IEqualityComparer<T> CreateComparer<V>(Func<T, V> keySelector, 
                                                         IEqualityComparer<V> comparer)
    {
        return new KeyEqualityComparer<V>(keySelector, comparer);
    }

    class KeyEqualityComparer<V> : IEqualityComparer<T>
    {
        readonly Func<T, V> keySelector;
        readonly IEqualityComparer<V> comparer;

        public KeyEqualityComparer(Func<T, V> keySelector, 
                                   IEqualityComparer<V> comparer)
        {
            if (keySelector == null)
                throw new ArgumentNullException("keySelector");

            this.keySelector = keySelector;
            this.comparer = comparer ?? EqualityComparer<V>.Default;
        }

        public bool Equals(T x, T y)
        {
            return comparer.Equals(keySelector(x), keySelector(y));
        }

        public int GetHashCode(T obj)
        {
            return comparer.GetHashCode(keySelector(obj));
        }
    }
}

다음과 같이 사용할 수 있습니다.

var comparer1 = Equality<Person>.CreateComparer(p => p.ID);
var comparer2 = Equality<Person>.CreateComparer(p => p.Name);
var comparer3 = Equality<Person>.CreateComparer(p => p.Birthday.Year);
var comparer4 = Equality<Person>.CreateComparer(p => p.Name, StringComparer.CurrentCultureIgnoreCase);

사람은 간단한 수업입니다.

class Person
{
    public int ID { get; set; }
    public string Name { get; set; }
    public DateTime Birthday { get; set; }
}

3
키에 대한 비교자를 제공 할 수있는 구현을 제공하는 +1 유연성을 높이는 것 외에도 비교 및 ​​해싱 모두에 대한 권투 값 유형을 피할 수 있습니다.
devgeezer

2
이것은 여기서 가장 정답입니다. null 확인도 추가했습니다. 완전한.
nawfal

11
public class FuncEqualityComparer<T> : IEqualityComparer<T>
{
    readonly Func<T, T, bool> _comparer;
    readonly Func<T, int> _hash;

    public FuncEqualityComparer( Func<T, T, bool> comparer )
        : this( comparer, t => t.GetHashCode())
    {
    }

    public FuncEqualityComparer( Func<T, T, bool> comparer, Func<T, int> hash )
    {
        _comparer = comparer;
        _hash = hash;
    }

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

    public int GetHashCode( T obj )
    {
        return _hash( obj );
    }
}

확장명 :-

public static class SequenceExtensions
{
    public static bool SequenceEqual<T>( this IEnumerable<T> first, IEnumerable<T> second, Func<T, T, bool> comparer )
    {
        return first.SequenceEqual( second, new FuncEqualityComparer<T>( comparer ) );
    }

    public static bool SequenceEqual<T>( this IEnumerable<T> first, IEnumerable<T> second, Func<T, T, bool> comparer, Func<T, int> hash )
    {
        return first.SequenceEqual( second, new FuncEqualityComparer<T>( comparer, hash ) );
    }
}

@Sam (이 의견으로는 더 이상 존재하지 않음) : 동작을 조정하지 않고 코드를 정리하고 +1했습니다. stackoverflow.com/questions/98033/…
Ruben Bartelink

6

orip의 대답은 훌륭합니다.

더 쉽게 만드는 약간의 확장 방법이 있습니다.

public static IEnumerable<T> Distinct<T>(this IEnumerable<T> list, Func<T, object>    keyExtractor)
{
    return list.Distinct(new KeyEqualityComparer<T>(keyExtractor));
}
var distinct = foo.Distinct(x => x.ToLower())

2

나는 내 자신의 질문에 대답 할 것입니다. 사전을 집합으로 취급하기 위해 가장 간단한 방법은 집합 작업을 dict.Keys에 적용한 다음 Enumerable.ToDictionary (...)를 사용하여 사전으로 다시 변환하는 것 같습니다.


2

람다 식으로 IEqualityCompare 구현 (독일어 텍스트)의 구현 은 null 값을 처리하고 확장 메서드를 사용하여 IEqualityComparer를 생성합니다.

Linq 조합에서 IEqualityComparer를 만들려면 다음과 같이 작성해야합니다.

persons1.Union(persons2, person => person.LastName)

비교기 :

public class LambdaEqualityComparer<TSource, TComparable> : IEqualityComparer<TSource>
{
  Func<TSource, TComparable> _keyGetter;

  public LambdaEqualityComparer(Func<TSource, TComparable> keyGetter)
  {
    _keyGetter = keyGetter;
  }

  public bool Equals(TSource x, TSource y)
  {
    if (x == null || y == null) return (x == null && y == null);
    return object.Equals(_keyGetter(x), _keyGetter(y));
  }

  public int GetHashCode(TSource obj)
  {
    if (obj == null) return int.MinValue;
    var k = _keyGetter(obj);
    if (k == null) return int.MaxValue;
    return k.GetHashCode();
  }
}

형식 유추를 지원하기 위해 확장 방법을 추가해야합니다.

public static class LambdaEqualityComparer
{
       // source1.Union(source2, lambda)
        public static IEnumerable<TSource> Union<TSource, TComparable>(
           this IEnumerable<TSource> source1, 
           IEnumerable<TSource> source2, 
            Func<TSource, TComparable> keySelector)
        {
            return source1.Union(source2, 
               new LambdaEqualityComparer<TSource, TComparable>(keySelector));
       }
   }

1

단 하나의 최적화 : 가치 비교를 위해 위임하지 않고 즉시 사용 가능한 EqualityComparer를 사용할 수 있습니다.

또한 실제 비교 논리가 이제 이미 오버로드되었을 수있는 GetHashCode () 및 Equals ()에 유지되므로 구현이 더 깨끗해집니다.

코드는 다음과 같습니다.

public class MyComparer<T> : IEqualityComparer<T> 
{ 
  public bool Equals(T x, T y) 
  { 
    return EqualityComparer<T>.Default.Equals(x, y); 
  } 

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

개체에 GetHashCode () 및 Equals () 메서드를 오버로드하는 것을 잊지 마십시오.

이 게시물이 도움이되었습니다 : C #은 두 가지 일반적인 값을 비교

스시


1
에 대한 댓글에서 확인 된 NB 같은 문제 stackoverflow.com/questions/98033/...은 - obj.GetHashCode ()을 가정 어차피하는 것은 의미가 있습니다
루벤 Bartelink

4
나는 이것의 목적을 얻지 못한다. 기본 같음 비교 자와 동등한 같음 비교자를 만들었습니다. 왜 직접 사용하지 않습니까?
코드 InChaos

1

orip의 대답 은 훌륭합니다. orip의 답변을 확장 :

솔루션의 핵심은 "익명 유형"을 전송하기 위해 "확장 방법"을 사용하는 것입니다.

    public static class Comparer 
    {
      public static IEqualityComparer<T> CreateComparerForElements<T>(this IEnumerable<T> enumerable, Func<T, object> keyExtractor)
      {
        return new KeyEqualityComparer<T>(keyExtractor);
      }
    }

용법:

var n = ItemList.Select(s => new { s.Vchr, s.Id, s.Ctr, s.Vendor, s.Description, s.Invoice }).ToList();
n.AddRange(OtherList.Select(s => new { s.Vchr, s.Id, s.Ctr, s.Vendor, s.Description, s.Invoice }).ToList(););
n = n.Distinct(x=>new{Vchr=x.Vchr,Id=x.Id}).ToList();

0
public static Dictionary<TKey, TValue> Distinct<TKey, TValue>(this IEnumerable<TValue> items, Func<TValue, TKey> selector)
  {
     Dictionary<TKey, TValue> result = null;
     ICollection collection = items as ICollection;
     if (collection != null)
        result = new Dictionary<TKey, TValue>(collection.Count);
     else
        result = new Dictionary<TKey, TValue>();
     foreach (TValue item in items)
        result[selector(item)] = item;
     return result;
  }

이를 통해 다음과 같이 람다가있는 속성을 선택할 수 있습니다. .Select(y => y.Article).Distinct(x => x.ArticleID);


-2

기존 수업을 모르지만 다음과 같은 것이 있습니다.

public class MyComparer<T> : IEqualityComparer<T>
{
  private Func<T, T, bool> _compare;
  MyComparer(Func<T, T, bool> compare)
  {
    _compare = compare;
  }

  public bool Equals(T x, Ty)
  {
    return _compare(x, y);
  }

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

참고 : 실제로 컴파일하고 아직 실행하지 않았으므로 오타 또는 다른 버그가있을 수 있습니다.


1
에 대한 댓글에서 확인 된 NB 같은 문제 stackoverflow.com/questions/98033/...은 - obj.GetHashCode ()을 가정 어차피하는 것은 의미가 있습니다
루벤 Bartelink
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.