2009-05-19 2 views
4

현재 동등 비교를 직접 정의 할 수있는 HashSet<T> 생성자는 HashSet<T>(IEqualityComparer<T> comparer) 생성자입니다. 이 EqualityComparer를 람다 (lambda)로 정의하고 싶습니다.사용자 정의 IEqualityCompare가 lambda로 정의 된 HashSet 생성자?

람다를 통해 비교자를 생성 할 수있는 클래스를 만든 this blog post을 찾은 다음 Except()와 같은 확장 메서드를 사용하여이 클래스의 생성을 숨 깁니다.

이제 생성자를 사용하여 같은 작업을 수행하려고합니다. 확장 메서드를 통해 생성자를 만들 수 있습니까? 아니면 어떻게 든 HashSet<T>(Func<T,T,int> comparer)을 만들 수있는 다른 방법이 있습니까? 더 이상적으로

HashSet<FileInfo> resultFiles = new HashSet<FileInfo>(
    srcPath.GetFiles(), 
    new LambdaComparer<FileInfo>(
     (f1, f2) => f1.Name.SubString(10).Equals(f2.Name.SubString(10)))); 

또는

HashSet<FileInfo> resultFiles = new HashSet<FileInfo>(
    srcPath.GetFiles(), 
    (f1, f2) => f1.Name.SubString(10).Equals(f2.Name.SubString(10))); 
을 : 명확성을 위해

--UPDATE--
,이 (의 조각) 내가 달성하기 위해 노력하고있어의 자유 버전입니다

+3

. 블로그에 댓글을 달았습니다. –

답변

5

아니요, 생성자를 추가 할 수 없습니다 (확장 메소드 포함).

당신이 IEqualityComparer<T>Func<T,T,int>에서 얻을 수있는 마법 방법이 가정 (당신이 그것을 인용 수 있다면 나는 그 블로그 게시물을 읽기에 관심이있을 것입니다) - 당신이 할 수있는 가장 가까운 아마 같은 것입니다 :

public static class HashSet { 
    public static HashSet<T> Create<T>(Func<T, T, int> func) { 
     IEqualityComparer<T> comparer = YourMagicFunction(func); 
     return new HashSet<T>(comparer); 
    } 
} 

그러나; 나는 평등을 위해 람다로 할 수있는 일에 대해 의심 스럽다 ... 해싱과 진정한 평등이라는 두 가지 개념을 표현해야한다. 람다는 어떻게 생겼을까요?

class Person { 
    public string Name { get; set; } 
    static void Main() { 
     HashSet<Person> people = HashSetHelper<Person>.Create(p => p.Name); 
     people.Add(new Person { Name = "Fred" }); 
     people.Add(new Person { Name = "Jo" }); 
     people.Add(new Person { Name = "Fred" }); 
     Console.WriteLine(people.Count); 
    } 
} 
public static class HashSetHelper<T> { 
    class Wrapper<TValue> : IEqualityComparer<T> { 
     private readonly Func<T, TValue> func; 
     private readonly IEqualityComparer<TValue> comparer; 
     public Wrapper(Func<T, TValue> func, 
      IEqualityComparer<TValue> comparer) { 
      this.func = func; 
      this.comparer = comparer ?? EqualityComparer<TValue>.Default; 
     } 
     public bool Equals(T x, T y) { 
      return comparer.Equals(func(x), func(y)); 
     } 

     public int GetHashCode(T obj) { 
      return comparer.GetHashCode(func(obj)); 
     } 
    } 
    public static HashSet<T> Create<TValue>(Func<T, TValue> func) { 
     return new HashSet<T>(new Wrapper<TValue>(func, null)); 
    } 
    public static HashSet<T> Create<TValue>(Func<T, TValue> func, 
     IEqualityComparer<TValue> comparer) 
    { 
     return new HashSet<T>(new Wrapper<TValue>(func, comparer)); 
    } 
} 
+1

죄송합니다. 블로그 게시물에 대한 링크를 잊어 버렸습니다. OP 갱신. 나는 OP에 대한 나의 진짜 표적을 설명 할 것이다. –

+0

블로그 게시물이 연결되어 있지만 내게 부러졌습니다. 가장 간단한 투영 비교조차도 해시가 사용되는 모든 경우에이를 비교합니다. –

+0

글쎄, 그때 그걸 정착. "없다"는 대답 인 것 같다. –

1

마크가 맞다 : 당신은 자식 속성으로 연기하려는 경우 ... 뭔가를 다음 아마도 Func<T,TValue>는 속성을 선택하고, 내부적으로 EqualityComparer<TValue>.Default를 사용합니다. 단일 람다가 Equals 및 GetHashCode에 필요한 정보를 표현하는 간단한 방법은 없습니다. "equal"요소에 대해 다른 해시를 반환하는 GetHashCode를 제공하면 잘못된 동작이 발생합니다.

내 타협안을 작성했습니다. 그것은 어떤 일반적인 Func (Marc와 같이, 당신이 설명하지 않았기 때문에 int를 무시했다)를 허용 할 것이고, 그것은 (그것이 계약을 준수한다는 점에서) 옳은 것을 줄 것이다. 그러나 매우 비효율적 인 행동이다.

귀하의 요구에 맞는 실제 IEqualityComparer를 사용하는 것이 좋습니다. C#은 익명의 내부 클래스를 지원하지 않습니다. 그냥 평등 기능과 호환되지 않는 해시로 이어질 것입니다 원래의 해시 코드를 호출하여 해시 코드를 생성 - 블로그 게시물이 IMO 파손 된 것으로

public static class HashSetDelegate 
{ 
    public static HashSet<T> Create<T>(Func<T, T, bool> func) 
    { 
    return new HashSet<T>(new FuncIEqualityComparerAdapter<T>(func)); 
    } 

    private class FuncIEqualityComparerAdapter<U> : IEqualityComparer<U> 
    { 
    private Func<U, U, bool> func; 
    public FuncIEqualityComparerAdapter(Func<U, U, bool> func) 
    { 
     this.func = func; 
    } 

    public bool Equals(U a, U b) 
    { 
     return func(a, b); 
    } 

    public int GetHashCode(U obj) 
    { 
     return 0; 
    } 

    } 
} 

public class HashSetTest 
{ 
    public static void Main() 
    { 
    HashSet<string> s = HashSetDelegate.Create((string a, string b) => string.Compare(a, b, true) == 0); 
    } 
} 
+0

글쎄, 네, 지금은 사용자 정의 Comparer 클래스로 해결했지만 더 나은 솔루션을 찾기 위해 좋은 훈련이 될 것이라고 생각했습니다. 비록 진짜 좋은 해결책이 없다고 보입니다. –

관련 문제