6

私に似たさまざまな質問を読みましたが、どれも私の問題に対処していないようです。

私はこのようなタイプを持っています:

class MyObject<T> : IEquatable<MyObject<T>> { // no generic constraints
  private readonly string otherProp;
  private readonly T value;

  public MyObject(string otherProp, T value)
  {
    this.otherProp = otherProp;
    this.value = value;
  }

  public string OtherProp { get { return this.otherProp; } }

  public T Value { get { return this.value; } }

  // ...

  public bool Equals(MyObject<T> other)
  {
    if (other == null)
    {
       return false;
    }

    return this.OtherProp.Equals(other.OtherProp) && this.Value.Equals(other.Value);
  }
}

等式が正しく機能するときTはスカラーですが、等号のようなものを定義すると失敗します。MyObject<int>MyObject<IEnumerable<int>>

その理由は、 T のときIEnumerable<T>に を呼び出す必要があるからthis.Value.SequenceEqual(other.Value)です。

この違いを処理Equals(MyObject<T>)すると、型チェックとリフレクションの LOC が多すぎます (私にとっては、SOLID/SRP の違反につながります)。

MSDN ガイドラインでこの特定のケースを見つけることができなかったので、誰かがすでにこの問題に直面している場合は、この知識が共有できれば素晴らしいことです。

編集:代替

KISSに、私は似たようなことをしたいと思っています:

class MyObject<T> : IEquatable<MyObject<T>> {
  private readonly IEnumerable<T> value;

  // remainder omitted
}

このようにして、の実装はEqual非常に簡単になります。値が 1 つだけ必要な場合は、1 つのアイテムのコレクションがあります。明らかに、 T は列挙可能ではありません (ただし、データ構造はプライベートであるため、問題はありません)。

4

4 に答える 4

4

Tisの場合IEnumerable<T>、コードは の 2 つの参照を比較しますIEnumerable<T>。もちろん、これらの参照は等しくない場合があります。実際、T がオーバーライドされEqualsたメソッドのない任意の参照型になると、この動作が得られます。

ここで参照を比較したくない場合は、これらのシーケンスを内容で比較するコードを記述する必要があります。ただし、そのシーケンスは無限に続く可能性があることに注意してください。

于 2013-03-19T08:31:01.710 に答える
3

MyObject<T>あなたのタイプの等値比較子を取り、それを使用することができますT

class MyObject<T> : IEquatable<MyObject<T>>
{
    private readonly IEqualityComparer<T> comparer;
    public MyObject(string otherProp, T value, IEqualityComparer<T> comparer)
    {
        this.comparer = comparer;
    }
    public MyObject(string otherProp, T value)
        : this(otherProp, value, EqualityComparer<T>.Default)
    {
    }

    public bool Equals(MyObject<T> other)
    {
        return OtherProp.Equals(other.OtherProp) && comparer.Equals(this.Value, other.Value);
    }
}

次にIEnumerable<T>、参照の代わりにシーケンスを比較する比較子を使用できます。ファクトリ メソッドを使用してオブジェクトを作成し、同じ比較型が同じものに使用されて、同等T性が対称に保たれるようにすることができます。

于 2013-03-19T08:37:35.590 に答える
1

これは、ヘルパー クラスの助けを借りる必要がある場合です。 MyObject タイプは、個々の EqualityChecker を利用する場合があります。

静的ファクトリ メソッドを使用して戦略パターンを実装すると、設計が簡素化されます。

以下のようなもの

class MyObject<T> : IEquatable<MyObject<T>>
{ // no generic constraints
    private readonly string otherProp;
    private readonly T value;

    public MyObject(string otherProp, T value)
    {
        this.otherProp = otherProp;
        this.value = value;
    }

    public string OtherProp { get { return this.otherProp; } }

    public T Value { get { return this.value; } }

    // ...

    public bool Equals(MyObject<T> other)
    {
        if (other == null)
        {
            return false;
        }

     var cheker =   EqualityChekerCreator<T>.CreateEqualityChecker(other.Value);

     if (cheker != null)
         return cheker.CheckEquality(this.Value, other.value);

        return this.OtherProp.Equals(other.OtherProp) && this.Value.Equals(other.Value);
    }
}

public static class  EqualityChekerCreator<T>
{
    private static IEqualityCheker<T> checker;

    public static IEqualityCheker<T>  CreateEqualityChecker(T type)
    {
        var currenttype = type as IEnumerable<T>;

        if(currenttype!=null)
            checker = new SequenceEqualityChecker<T>();

        return checker;
    }
}

public  interface  IEqualityCheker<in T>
{
    bool CheckEquality(T t1, T t2);
}

public class SequenceEqualityChecker <T> : IEqualityCheker<T>
{
    #region Implementation of IEqualityCheker<in T>

    public bool CheckEquality(T t1, T t2)
    {
        // implement method here;
    }

    #endregion
}
于 2013-03-19T08:34:50.063 に答える
1

反省は必要ありません。1 つのオプションは、Equals メソッドで値が IEnumerable かどうかを確認することです。

IEnumerable e = other.Value as IEnumerable;

if(e != null){
 // use  SequenceEqual
}else{
 // use Equals
}
于 2013-03-19T08:30:33.877 に答える