2009-05-19 1 views
4

現在、HashSet<T>のコンストラクタでは、均等比較を自分で定義することができます。これはHashSet<T>(IEqualityComparer<T> comparer)コンストラクタです。 このEqualityComparerをラムダとして定義したいと思います。ラムダで定義されたカスタムIEqualityCompareを持つHas​​hSetコンストラクタ?

ラムダを通して比較者を生成させるクラスを作ったクラスを作ってから、Except()などのエクステンションメソッドを使ってこのクラスの構造を隠すことができました。

私は同じことをやっていますが、コンストラクタを使用したいと思います。エクステンションメソッドを使ってコンストラクタを作成することは可能ですか?または、何とか私がHashSet<T>(Func<T,T,int> comparer)を作成する別の方法がありますか?明確にするために

--UPDATE--
、これは私が達成しようとしているもののフリーハンドバージョン(の抜粋)です:

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))); 
+3

ブログの投稿が壊れているIMO - 元のハッシュコードを呼び出すだけでハッシュコードが生成されます。ハッシュコードは、等価関数と互換性のないハッシュにつながります。私はブログにコメントしました。 –

答えて

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); 
    } 
} 

ただし、私はあなたが平等のためにラムダでできることについて疑念を抱いています...表現する二つの概念があります:ハッシュと真の平等。あなたのラムダはどのように見えますか?あなたは子プロパティに延期しようとしている場合は、おそらくFunc<T,TValue>は、プロパティを選択し、内部EqualityComparer<TValue>.Defaultを使用して...のようなもの:

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

マークは右です。単一のラムダがEqualsとGetHashCodeの両方に必要な情報を表現する簡単な方法はありません。また、等しい要素に対して異なるハッシュを返すGetHashCodeを提供すると、不正な動作が発生します。

これは私の妥協の実装です。それは、一般的なFunc(私はあなたがそれを説明しなかったので、Marcのようにintを無視する)を許可し、それは正しい(それが契約に準拠している)が、非常に非効率的な振る舞いを与えます。

あなたのニーズを満たす実際のIEqualityComparerを使用することをお勧めします。 C#では匿名の内部クラスはサポートされていませんが、残念です。

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クラスを使って解決しましたが、もっと良い解決策を探し出すのがいいと思いました。しかし、本当の素晴らしい解決策はないようだ。 –

関連する問題