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).

使用类型检查和反射的 LOC 来处理这种差异会膨胀Equals(MyObject<T>)(对我来说,这会导致违反 SOLID/SRP)。

我无法在 MSDN 指南中找到这个特定案例,所以如果有人已经遇到过这个问题;如果可以分享这些知识,那就太好了。

编辑:替代

对于 KISS,我想知道做类似的事情:

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

  // remainder omitted
}

这样实现起来Equal就会简单很多。当我只需要一个值时,我会收集 1 个项目。显然 T 不会是可枚举的(但数据结构是私有的,所以没有问题)。

4

4 回答 4

4

如果什么时候TIEnumerable<T>,您的代码会比较两个引用IEnumerable<T>,当然,这些引用可能不相等。Equals实际上,当 T 是没有重写方法的任何引用类型时,您会得到这种行为。

如果您不想在这里比较引用,您应该编写一个代码,该代码将通过它们的内容比较这些序列。但是,您应该注意,该序列可能是无止境的。

于 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

不需要反思。一种选择是在 Equals 方法中检查 value 是否为 IEnumerable:

IEnumerable e = other.Value as IEnumerable;

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

在这种情况下,您应该借助 helper 类,您的 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 回答