2010-04-29 91 views
114

我希望我的Food类能够测试何时它等于另一个实例Food。稍后我将使用它来对付List,并且我想使用它的List.Contains()方法。我应该执行IEquatable<Food>还是只覆盖Object.Equals()?从MSDN:IEquatable和刚刚重写Object.Equals()之间有什么区别?

此方法,使用默认的相等比较, 如由对象的 实现对于T (值的列表中的类型)的 IEquatable.Equals方法的定义由 确定平等。

所以我的下一个问题是:.NET框架的哪些函数/类使用Object.Equals()?我应该首先使用它吗?

+2

这里很好的解释http://blogs.msdn.com/b/jaredpar/archive/2009/01/15/if-you-implement-iequatable-t-you-still-must-override-object- s-equals-and-gethashcode.aspx – nawfal 2013-04-14 12:13:49

+1

@nawfal:在接受的答案中已经提到过。 – 2013-04-14 16:50:12

+0

[Understanding IEquatable](http://stackoverflow.com/questions/411500/understanding-iequatable)可能的重复 – nawfal 2013-10-08 05:19:23

回答

140

主要原因是表现。当在.NET 2.0中引入泛型时,他们能够添加一堆整齐的类,如List<T>,Dictionary<K,V>,HashSet<T>等。这些结构大量使用GetHashCodeEquals。但对于价值类型,这需要拳击。 IEquatable<T>让一个结构实现强类型Equals方法,因此不需要装箱。因此,在使用泛型集合的值类型时性能会好得多。

参考类型没有太多好处,但IEquatable<T>实现允许您避免来自System.Object的强制转换,如果频繁调用它可能会产生影响。

虽然在Jared Parson's blog上指出,但你仍然必须实现Object overrides。

+0

引用类型之间是否存在任何转换?我一直认为,当你将一些不明显的对象从一种对象分配给另一种对象时,对于编译器来说,强制转换只是“声明”。在编译之后,代码甚至不知道那里是否有投射。 – 2010-04-29 05:41:50

+5

这在C++中是正确的,但不是强制类型安全的.NET语言。有一个运行时间转换,如果转换不成功,则抛出异常。所以在铸造时需要花费很少的运行时间。编译器可以优化掉upcasts例如object o =(object)“string”;但是向下转换 - string s =(string)o; - 必须在运行时发生。 – Josh 2010-04-29 05:58:53

+1

我明白了。偶然的情况下,你有什么地方可以获得关于.NET的那种“更深入”的信息?谢谢! – 2010-04-29 06:03:39

34

按照MSDN:的 Object.Equals(Object)GetHashCode 使他们的行为是一致的 与该IEquatable(T).Equals 方法

如果实现IEquatable(T),你 也应该覆盖基类 实现。如果您确实覆盖了 Object.Equals(Object),那么您的类的静态Equals(System.Object, System.Object)方法中的调用 也会调用您的重写的 实现。 这确保所有调用 的Equals方法返回一致的 结果。

因此,似乎两者之间没有真正的功能差异,除非可以根据类的使用方式来调用。从性能角度来看,它更好地使用通用版本,因为不存在与其相关的装箱/拆箱处罚。

从逻辑的角度来看,实现接口也更好。重写对象并不能真正告诉任何人你的类实际上是可以相等的。重写可能只是一个无所事事的类或浅层实现。明确地使用接口说:“嘿,这个东西适用于平等检查!”这只是更好的设计。

+0

是的,他们都是好点。 – 2010-04-29 05:42:22

+4

如果结构体将用作Dictionary或类似集合中的键,那么它肯定应该实现iEquatable(ofOwnType);它将提供重大的性能提升。通过实现IEquatable(的OwnType),非继承类将获得轻微的性能提升。可继承的类应该// //不实现IEquatable。 – supercat 2010-12-07 16:34:31

19

扩展Josh说的一个实际例子。+1给Josh - 我正要在我的回答中写下同样的内容。

public abstract class EntityBase : IEquatable<EntityBase> 
{ 
    public EntityBase() { } 

    #region IEquatable<EntityBase> Members 

    public bool Equals(EntityBase other) 
    { 
     //Generic implementation of equality using reflection on derived class instance. 
     return true; 
    } 

    public override bool Equals(object obj) 
    { 
     return this.Equals(obj as EntityBase); 
    } 

    #endregion 
} 

public class Author : EntityBase 
{ 
    public Author() { } 
} 

public class Book : EntityBase 
{ 
    public Book() { } 
} 

这样一来,我已经重新使用equals()方法是比较适合我的所有派生类的盒子的方法。

+0

还有一个问题。使用“obj作为EntityBase”而不是(EntityBase)obj有什么优势?只是一个风格问题,或者有什么优势?在“obj为EntityBase”的情况下为 – 2010-04-29 05:44:49

+15

- 如果obj不是EntityBase类型,它将传递“null”并继续而没有任何错误或异常,但是在“(EntityBase)obj”的情况下,它会强制尝试obj到EntityBase,如果obj不是EntityBase类型,则会抛出InvalidCastException。是的,“as”只能应用于参考类型。 – 2010-04-29 06:05:16

+0

啊,我明白了。大。谢谢! – 2010-04-29 06:08:31

相关问题