我读过与我类似的各种问题,但似乎都没有解决我的问题。
我的类型是这样的:
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>)
过于局部的类型检查和反射(对我来说,导致违反SOLID / SRP)。
我无法在MSDN指南中找到这个具体案例,所以如果有人已经遇到过这个问题;如果可以分享这些知识,那就太好了。
编辑:替代
对于K.I.S.S.,我想知道做类似的事情:
class MyObject<T> : IEquatable<MyObject<T>> {
private readonly IEnumerable<T> value;
// remainder omitted
}
通过这种方式Equal
的实现将非常简单。当我只需要一个值时,我就收集了1个项目。
显然T不是可枚举的(但数据结构是私有的,所以没有问题)。
答案 0 :(得分:4)
如果T
为IEnumerable<T>
,您的代码会比较IEnumerable<T>
的两个引用,当然,这些引用可能不相等。实际上,当T没有被覆盖的Equals
方法的任何引用类型时,你会得到这种行为。
如果你不想在这里比较引用,你应该编写一个代码,它将按照内容比较这些序列。但是,你应该注意,这个序列可能是无穷无尽的。
答案 1 :(得分: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
使用相同的比较器类型,以确保相等性保持对称。
答案 2 :(得分:1)
不需要反思。一种选择是在Equals方法中检查值是否为IEnumerable:
IEnumerable e = other.Value as IEnumerable;
if(e != null){
// use SequenceEqual
}else{
// use Equals
}
答案 3 :(得分: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
}