假设我有一个通用MyClass<T>
,需要比较两个<T>
类型的对象。通常我会做... ...
void DoSomething(T o1, T o2)
{
if(o1.Equals(o2))
{
...
}
}
现在假设我的MyClass<T>
有一个支持传递自定义IEqualityComparer<T>
的构造函数,类似于Dictionary<T>
。在那种情况下,我需要做......
private IEqualityComparer<T> _comparer;
public MyClass() {}
public MyClass(IEqualityComparer<T> comparer)
{
_comparer = comparer;
}
void DoSomething(T o1, T o2)
{
if((_comparer != null && _comparer.Equals(o1, o2)) || (o1.Equals(o2)))
{
...
}
}
要删除这个冗长的if语句,如果使用常规构造函数,我可以将_comparer
默认为'default comparer'。我搜索了typeof(T).GetDefaultComparer()
之类的东西,却找不到类似的东西。
我找到EqualityComparer<T>.Default
,我可以使用吗?然后这个片段......
public MyClass()
{
_comparer = EqualityComparer<T>.Default;
}
void DoSomething(T o1, T o2)
{
if(_comparer.Equals(o1, o2))
{
...
}
}
...提供与使用o1.Equals(o2)
所有可能情况相同的结果?
(作为旁注,这是否意味着我还需要对<T>
使用任何特殊的通用约束?)
答案 0 :(得分:39)
它应该是相同的,但不能保证,因为它取决于T
类型的实现细节。
说明:
如果没有T
的约束,即使Object.Equals
实施T
,o1.Equals(o2)也会调用IEquatable<T>
。
EqualityComparer<T>.Default
但是,如果Object.Equals
未实现T
,则仅使用IEquatable<T>
。如果 实现该界面,则使用IEquatable<T>.Equals
只要T
执行Object.Equals
只调用IEquatable<T>.Equals
,结果就是相同的。但在下面的例子中,结果并不相同:
public class MyObject : IEquatable<MyObject>
{
public int ID {get;set;}
public string Name {get;set;}
public override bool Equals(object o)
{
var other = o as MyObject;
return other == null ? false : other.ID == ID;
}
public bool Equals(MyObject o)
{
return o.Name == Name;
}
}
现在,实现这样的类没有任何意义。但如果MyObject
的实施者忘记覆盖Object.Equals
,您将遇到同样的问题。
结论:
使用EqualityComparer<T>.Default
是一个很好的方法,因为你不需要支持错误的对象!
答案 1 :(得分:3)
默认情况下,在类中重写之前,Object.Equals(a,b)
/ a.Equals(b)
会按引用进行比较。
EqualityComparer<T>.Default
将返回什么比较器取决于T
。例如,如果T : IEquatable<>
,则会创建相应的EqualityComparer<T>
。
答案 2 :(得分:2)
您可以使用null coaelescense运算符??缩短if if是否真的重要
if ((_comparer ?? EqualityComparer<T>.Default).Equals(o1, o2))
{
}
答案 3 :(得分:2)
如果在构造对象时没有指定比较器,那么这正是BCL中的Dictionary<>
和其他泛型集合所做的。这样做的好处是EqualityComparer<T>.Default
将为IEquatable<T>
类型,可空类型和枚举返回正确的比较器。如果T不是那些,它将进行简单的Equals比较,就像你的旧代码正在做的那样。
答案 4 :(得分:2)
是的,我认为使用EqualityComparer<T>.Default
是明智的,因为如果类型IEquatable<T>
实现T
,或者覆盖Object.Equals
,它会使用private IEqualityComparer<T> _comparer;
public IEqualityComparer<T> Comparer
{
get { return _comparer?? EqualityComparer<T>.Default;}
set { _comparer=value;}
}
public MyClass(IEqualityComparer<T> comparer)
{
_comparer = comparer;
}
void DoSomething(T o1, T o2)
{
if(Comparer.Equals(o1, o2))
{
...
}
}
的实现} 除此以外。你可以这样做:
{{1}}