天道酬勤,学无止境

IEquatable, how to implement this properly [duplicate]

I am using .net 2.0 and c# and I have implemented the IEquatible interface in my class like this:-

public MyClass() :  IEquatable<MyClass>
{
    Guid m_id = Guid.NewGuid();

    public Guid Id
    {
        get
        {
            return m_id;
        }
    }

    #region IEquatable<MyClass> Members

    public bool Equals(MyClass other)
    {
        if (this.Id == other.Id)
        {
            return true;
        }
        else
        {
            return false;
        }
    }

    #endregion
}

Is this bad programming practice? I've read that I also need to implement Object.Equals and Object.GetHashCode as well, but I am not sure why.

I want to be able to check that an instance of MyClass is not already contained in a generic list of type MyClass. Why does the framework only suggests that you implement Equals only?

Any help would be greatly appreciated.

标签

评论

You can check if your list contains an item using a custom predicate for the criteria, using LINQ. In that case you don't need to override Equals nor implement IEquatable:

// check if the list contains an item with a specific ID
bool found = someList.Any(item => item.ID == someId);

Overriding Equals (with GetHashCode) and implementing IEquatable is useful if you need to store your item in a Dictionary or a Hashtable.

Is this bad programming practice?

Implementing IEquatable<T> is great, even more so for structs, but merely doing that much is not enough.

I've read that I also need to implement Object.Equals

Read it here why..

and Object.GetHashCode as well, but I am not sure why.

Read it here and here. Seriously, these have been discussed so many times, and it is pretty simple.. In short, you need it for collection types that deals with hashes like Dictionary<,> or HashSet<>

I want to be able to check that an instance of MyClass is not already contained in a generic list of type MyClass. Why does the framework only suggests that you implement Equals only?

Depends on the collection type. For a List<T>, it will check equality merely based on how you have defined Equals method, say for Contains method. For most scenario you will need Equals only. But if you have a HashSet<T> then absence and presence checks will utilize hash of your objects. Framework indeed asks us to implement good hashing approaches (without re-inventing the wheel) at appropriate places.

Any help would be greatly appreciated.

Do as below, but you have to overload operators == and != only if it make sense to you. Seeing your class I assumed its ok to have value semantics for your class. Otherwise just ignore that part (if == should mean reference equality)... Getting hashcode from your guid would suffice, provided that is all you need to test equality.

public sealed class MyClass : IEquatable<MyClass>
{
    Guid m_id = Guid.NewGuid();

    public Guid Id { get { return m_id; } }

    public bool Equals(MyClass other)
    {
        if (ReferenceEquals(this, other))
            return true;

        if (ReferenceEquals(null, other))
            return false;

        return Id == other.Id; 
    }

    public override bool Equals(object obj)
    {
        return Equals(obj as MyClass);
    }

    public static bool operator ==(MyClass lhs, MyClass rhs)
    {
        if (ReferenceEquals(lhs, null))
            return ReferenceEquals(rhs, null);

        return lhs.Equals(rhs);
    }

    public static bool operator !=(MyClass lhs, MyClass rhs)
    {
        return !(lhs == rhs);
    }

    public override int GetHashCode()
    {
        return Id.GetHashCode();
    }   
}

To not get it wrong, make use of the snippet available here: For a good overview see this SO thread.

受限制的 HTML

  • 允许的HTML标签:<a href hreflang> <em> <strong> <cite> <blockquote cite> <code> <ul type> <ol start type> <li> <dl> <dt> <dd> <h2 id> <h3 id> <h4 id> <h5 id> <h6 id>
  • 自动断行和分段。
  • 网页和电子邮件地址自动转换为链接。

相关推荐
  • .Except(LINQ)为什么不能正确比较事物? (使用IEquatable)(Why isn't .Except (LINQ) comparing things properly? (using IEquatable))
    问题 我有自己的引用类型对象的两个集合,我为它们编写了自己的IEquatable.Equals方法,并且希望能够在它们上使用LINQ方法。 所以, List<CandyType> candy = dataSource.GetListOfCandy(); List<CandyType> lollyPops = dataSource.GetListOfLollyPops(); var candyOtherThanLollyPops = candy.Except( lollyPops ); 根据.Except的文档,未传递IEqualityComparer会导致EqualityComparer.Default用于比较对象。 默认比较器的文档是这样的: “ Default属性检查类型T是否实现System.IEquatable通用接口,如果是,则返回使用该实现的EqualityComparer。否则,它返回一个EqualityComparer,该EqualityComparer使用T提供的Object.Equals和Object.GetHashCode的替代。” 因此,因为我为我的对象实现了IEquatable,所以它应该使用它并起作用。 但是,事实并非如此。 直到我重写GetHashCode,它才起作用。 实际上,如果设置断点,则IEquatable.Equals方法将永远不会执行。
  • 是否有完整的IEquatable实现参考?(Is there a complete IEquatable implementation reference?)
    问题 我在SO上的许多问题都与IEquatable实现有关。 我发现很难正确实施,因为天真的实现中存在许多隐藏的错误,而我发现的文章还很不完整。 我想查找或编写明确的参考资料,其中必须包括: 如何正确实现IEquatable 如何正确覆盖等于如何正确覆盖GetHashCode 如何正确实现ToString方法如何正确实现运算符== 如何正确实现运算符!= 这样完整的参考资料已经存在了吗? PS:即使MSDN参考似乎对我来说也是有缺陷的 回答1 为值类型实现IEquatable<T> 为值类型实现IEquatable<T>与引用类型略有不同。 假设我们具有“实现自己的价值类型”原型,即“复数”结构。 public struct Complex { public double RealPart { get; set; } public double ImaginaryPart { get; set; } } 我们的第一步将是实现IEquatable<T>并重写Object.Equals和Object.GetHashCode : public bool Equals(Complex other) { // Complex is a value type, thus we don't have to check for null // if (other == null) return
  • Why isn't .Except (LINQ) comparing things properly? (using IEquatable)
    I have two collections of my own reference-type objects that I wrote my own IEquatable.Equals method for, and I want to be able to use LINQ methods on them. So, List<CandyType> candy = dataSource.GetListOfCandy(); List<CandyType> lollyPops = dataSource.GetListOfLollyPops(); var candyOtherThanLollyPops = candy.Except( lollyPops ); According to the documentation of .Except, not passing an IEqualityComparer should result in EqualityComparer.Default being used to compare objects. And the documentation for the Default comparer is this: "The Default property checks whether type T implements the
  • 如何列出 .IndexOf()对自定义对象执行比较?(How does List<T>.IndexOf() perform comparisons on custom objects?)
    问题 我编写了一个帐户对象类,并持有这些帐户对象的静态List<T> 。 我的程序遍历列表中的每个帐户,对该帐户执行一些工作,然后在到达列表末尾时在顶部重新设置。 我的问题是我的程序在使用完该帐户后,需要能够将帐户重新插入列表中,并添加了一些更新的信息。 我可以使用IndexOf()函数按照下面的说明执行此操作,以检查静态列表中的对象吗,否则会因为添加数据而失败? 我不明白它比较哪些字段以查看两个对象是否相同。 注意:列表中不允许重复,因此没有更新错误项目的风险 public class Account { public string name; public string password; public string newInfo; } public static class Resources { private static List<Account> AccountList = new List<Account>(); private static int currentAccountIndex = 0; public static Account GetNextAccount() { if (currentAccountIndex > AccountList.Count) currentAccountIndex = 0; return AccountList
  • IComparable和IEquatable接口之间有什么区别?(What's the difference between IComparable & IEquatable interfaces?)
    问题 两个接口似乎都比较对象是否相等,那么它们之间的主要区别是什么? 回答1 IEquatable测试两个对象是否相等。 IComparable对要比较的对象施加总排序。 例如, IEquatable会告诉你,5不等于7 IComparable会告诉你,5来自7之前。 回答2 IEquatable<T>用于相等性。 IComparable<T>用于订购。 回答3 除了格雷格D的答案: 对于部分排序有意义的类,您可以实现IComparable而不实现IEquatable ,并且在该类中,您绝对希望使用者推断,因为CompareTo()返回零,这并不意味着对象相等(对于除排序目的)。 回答4 如IEquatable的MSDN页面上所述: IComparable接口定义CompareTo方法,该方法确定实现类型的实例的排序顺序。 IEquatable接口定义了Equals方法,该方法确定实现类型的实例的相等性。 Equals vs. CompareTo 回答5 IComparable <T>定义了一种特定于类型的比较方法,该方法可用于对对象进行排序或排序。 IEquatable <T>定义了一种通用方法,可用于实现确定相等性的方法。 假设您有Person类 public class Person { public string Name { get; set; } public int
  • 如何实现IEquatable 当可变字段是等式的一部分时 - GetHashCode 的问题(How to implement IEquatable<T> when mutable fields are part of the equality - Problem with GetHashCode)
    问题 我在我的应用程序中使用实体框架。 我用实体的部分类实现了IEquatable<T>接口: Partial Class Address : Implements IEquatable(Of Address) 'Other part generated Public Overloads Function Equals(ByVal other As Address) As Boolean _ Implements System.IEquatable(Of Address).Equals If ReferenceEquals(Me, other) Then Return True Return AddressId = other.AddressId End Function Public Overrides Function Equals(ByVal obj As Object) As Boolean If obj Is Nothing Then Return MyBase.Equals(obj) If TypeOf obj Is Address Then Return Equals(DirectCast(obj, Address)) Else Return False End Function Public Overrides Function GetHashCode() As
  • 为了确保平等正常运行,结构中需要覆盖哪些内容?(What needs to be overridden in a struct to ensure equality operates properly?)
    问题 如标题所示:是否需要覆盖==运算符? .Equals()方法怎么样? 我有什么想念的吗? 回答1 来自msdn的示例 public struct Complex { double re, im; public override bool Equals(Object obj) { return obj is Complex c && this == c; } public override int GetHashCode() { return re.GetHashCode() ^ im.GetHashCode(); } public static bool operator ==(Complex x, Complex y) { return x.re == y.re && x.im == y.im; } public static bool operator !=(Complex x, Complex y) { return !(x == y); } } 回答2 您还应该实现IEquatable <T>。 这是《框架设计指南》的摘录: 不要在值类型上实现IEquatable。 值类型上的Object.Equals方法会导致装箱,并且其默认实现不是很有效,因为它使用了染感。 IEquatable.Equals可以提供更好的性能,并且可以实现,从而不会引起装箱。 public
  • C#比较两个通用值(c# compare two generic values [duplicate])
    问题 这个问题已经在这里有了答案: 8年前关闭。 可能重复: 运算符==不能应用于C#中的泛型类型吗? 我已经编写了如下代码: public bool IsDataChanged() { T value1 = GetValue2; T value2 = GetValue1(); return (valueInDB != valueFromView); } 现在,该函数无法编译,并且错误“运算符'!='无法应用于类型为'T'和'T'的操作数”。 要使此功能正常工作,我该怎么办? 回答1 除非在T:class处添加表示其为引用类型的位置(否则foo == bar合法),否则不能对泛型类型使用运算符(除非foo == null例外)。 使用EqualityComparer<T>默认为您完成此操作。 这对类型不会工作,这仅适用于==提供一个操作符重载也没有任何: 实现IEquatable<T> 覆盖object.Equals() 总的来说,实现==运算符并且不同时执行其中至少之一将是一个非常糟糕的主意,因此这不太可能成为问题。 public bool IsDataChanged<T>() { T value1 = GetValue2; T value2 = GetValue1(); return !EqualityComparer<T>.Default.Equals(value1
  • 为什么 IEquatable T 没有在 C# 4.0 的 T 中实现逆变?(Why was IEquatable T not made contravariant in T for C# 4.0?)
    问题 IEquatable<T> 可以被声明为 T 中的逆变,因为它只在输入位置使用 T(或者,等效地,U 作为 T 的子类型应该意味着 IEquatable<T> 是 [a subtype of] IEquatable<U >)。 那么,为什么 BCL 团队没有像对许多其他通用接口(例如完全类似的 IComparable)那样使用 'in' 关键字对其进行注释(对于 C# 4.0)? 回答1 我认为这主要是出于哲学原因而不是技术限制——因为完全可以简单地对界面进行注释。 IEquatable<T>旨在比较相同类型的对象是否完全相等。 超类的实例通常不被认为等同于子类的实例。 这种意义上的平等也意味着类型平等。 这与IComparable<in T>有点不同。 定义跨不同类型的相对排序顺序是明智的。 在 IEquatable<T> 上引用 MSDN 页面: 给实施者的注意事项: 将IEquatable<T>接口的类型参数替换为实现此接口的类型。 这句话进一步证明了IEquatable<T>旨在在单个具体类型的实例之间工作。 回答2 可继承类型通常不应实现IEquatable<T> 。 如果IEquatable<T>包含GetHashCode()方法,则可以定义IEquatable<T>的语义,以说明项目在作为 T 进行检查时应该比较相等。 不幸的是, IEquatable<T
  • How to implement IEquatable<T> when mutable fields are part of the equality - Problem with GetHashCode
    I am using Entity Framework in my application. I implemented with the partial class of an entity the IEquatable<T> interface: Partial Class Address : Implements IEquatable(Of Address) 'Other part generated Public Overloads Function Equals(ByVal other As Address) As Boolean _ Implements System.IEquatable(Of Address).Equals If ReferenceEquals(Me, other) Then Return True Return AddressId = other.AddressId End Function Public Overrides Function Equals(ByVal obj As Object) As Boolean If obj Is Nothing Then Return MyBase.Equals(obj) If TypeOf obj Is Address Then Return Equals(DirectCast(obj, Address
  • 正确实现两个不同类型但语义等价的对象的比较(Properly implement comparison of two objects with different type but semantically equivalent)
    问题 我发现了一个类似的问题 如何比较具有相似属性的两个截然不同的对象 这可能暗示和/或部分回答我的问题。 假设我想比较(没有很多嵌套条件)这个对象: class ObjectA { public string PropertyX { get; set; } public char PropertyY { get; set; } public long PropertyZ { get; set; } } 到System.String 。 我只对平等或不平等感兴趣(不是关于身份的一系列价值观)。 实施IEquatable<string>在ObjectA是一个适当的选择? 我不在乎什么简单有效,我想为这种情况确定正确的模式。 作为其他信息,请考虑ObjectA通常作为IEnumerable<ObjectA>序列提供。 我不需要知道"string" ==还是!= objectA实例; 不涉及排序。 编辑以澄清(和帮助) 抱歉,写一个好问题有时很困难...... 假设我不能出于比较的目的将ObjectA表示为字符串(违反封装不是一种选择)。 在 context-1 中,我必须将它与PropertyY匹配。 在 context-2 中,我必须将它与应用于PropertyY / PropertyZ的算法进行匹配。 问题末尾的@Oliver 解决方案再次帮助我(再次+1)。
  • How to compare two list<object> in C# and retain only the items that don't have duplicates?(How to compare two list<object> in C# and retain only the items that don't have duplicates?)
    问题 Here are two lists: var list1 = new List<UserGroupMap> { new UserGroupMap { UserId = "1", GroupId = "1", FormGroupFlag = "1", GroupDescription = "desc1", GroupName = "g1"}, new UserGroupMap { UserId = "1", GroupId = "2", FormGroupFlag = "1", GroupDescription = "desc1", GroupName = "g1"}, new UserGroupMap { UserId = "1", GroupId = "3", FormGroupFlag = "1", GroupDescription = "desc1", GroupName = "g1"}, new UserGroupMap { UserId = "2", GroupId = "3", FormGroupFlag = "1", GroupDescription = "desc1", GroupName = "g1"} }; var list2 = new List<UserGroupMap> { new UserGroupMap { UserId = "1"
  • C#覆盖字典ContainsKey(C# override Dictionary ContainsKey)
    问题 我只是找不到任何合适的代码来满足我的需要。 我正在使用Dict.ContainsKey但是由于我总是创建我需要寻找的密钥的事实,因此对于ContainsKey我总是会得到false(因为hashKey是不同的并且我正在创建所有我想检查的密钥)。 有人可以建议在这种情况下如何覆盖包含密钥或如何处理密钥吗? 我的字典看起来像Dictionary<someObj, int> public class someObj { public int someobjParam {get;set;} public int someobjParamTwo {get;set;} } 回答1 您不需要重写ContainsKey ,而是在字典应认为两个键相等时指示字典。 一种方法是在您的键类中实现IEquatable <someObj>。 如果平等的概念在您的应用程序中是全球性的,请执行以下操作: public class someObj : IEquatable<someObj> { public int someobjParam {get;set;} public int someobjParamTwo {get;set;} // override GetHashCode() and Equals(); for an example // see http://msdn.microsoft.com
  • Dictionary.ContainsKey()-如何工作?(Dictionary.ContainsKey() - How does it work?)
    问题 我已经阅读了MSDN文档中Dictionary.ContainsKey()工作原理,但是我想知道它实际上是如何进行相等比较的? 基本上,我有一个键为引用类型*的字典,并且我希望ContainsKey()方法检查该引用类型的某个属性作为确定键是否存在的基础。 例如,如果我有一个Dictionary(MyObject, int)并且MyObject有一个名为“ TypeID”的公共属性( int ),我可以获取ContainsKey(MyObject myObject)来检查其中一个键是否具有TypeID为等于myObject吗? 我可以重载==运算符吗? 引用类型是一个名为“ Duration”的对象,其中包含一个值( double Length ); “持续时间”是我的音乐程序中使用的基本类型,用于表示特定声音持续多长时间。 我从中衍生出一些类,这些类中包含了更复杂的计时概念,例如西方音乐时标,但希望它们在长度上都具有可比性。 编辑:按照建议,我在对象上实现了IEquitable,如下所示: public class Duration : IEquatable<Duration> { protected double _length; /// <summary> /// Gets or Sets the duration in Miliseconds. /// <
  • T[].Contains 结构和类的行为不同(T[].Contains for struct and class behaving differently)
    问题 这是对此的后续问题: List<T>.Contains 和 T[].Contains 行为不同 当T是类和结构时, T[].Contains的行为有所不同。 假设我有这个结构: public struct Animal : IEquatable<Animal> { public string Name { get; set; } public bool Equals(Animal other) //<- he is the man { return Name == other.Name; } public override bool Equals(object obj) { return Equals((Animal)obj); } public override int GetHashCode() { return Name == null ? 0 : Name.GetHashCode(); } } var animals = new[] { new Animal { Name = "Fred" } }; animals.Contains(new Animal { Name = "Fred" }); // calls Equals(Animal) 在这里,如我所料,正确地调用了通用Equals 。 但如果是一个班级: public class Animal
  • 比较对象(Comparing objects)
    问题 我有一个类,它包含一些字符串成员、一些双精度成员和一些数组对象。 我创建了这个类的两个对象,有没有最简单、有效的方法来比较这些对象并说它们相等? 有什么建议么? 我知道如何编写比较函数,但这会很耗时。 回答1 真正做到这一点的唯一方法是覆盖bool Object.Equals(object other)以在满足相等条件时返回 true,否则返回 false。 您还必须覆盖int Object.GetHashCode()以返回根据覆盖Equals()时考虑的所有数据计算得出的 int。 GetHashCode() ,请注意GetHashCode()的约定指定当Equals()在比较它们时返回 true 时,两个对象的返回值必须相等。 这意味着return 0; 是GetHashCode()的有效实现,但是当您的类的对象用作字典键或存储在HashSet<T>时,它会导致效率低下。 我实现平等的方式是这样的: public class Foo : IEquatable<Foo> { public bool Equals(Foo other) { if (other == null) return false; if (other == this) return true; // Same object reference. // Compare this to other and
  • 与定制比较器不同的LinQ留下重复项(LinQ distinct with custom comparer leaves duplicates)
    问题 我有以下课程: public class SupplierCategory : IEquatable<SupplierCategory> { public string Name { get; set; } public string Parent { get; set; } #region IEquatable<SupplierCategory> Members public bool Equals(SupplierCategory other) { return this.Name == other.Name && this.Parent == other.Parent; } #endregion } public class CategoryPathComparer : IEqualityComparer<List<SupplierCategory>> { #region IEqualityComparer<List<SupplierCategory>> Members public bool Equals(List<SupplierCategory> x, List<SupplierCategory> y) { return x.SequenceEqual(y); } public int GetHashCode(List<SupplierCategory> obj)
  • Overriding IEquatable<T> when T is an interface and hashcodes are different between derived types
    I have A and B classes both implementing interface I. public interface I { int SomeInt { get; } bool SomeBool { get; } float SomeFloat { get; } } public class A : I { public int SomeInt { get; } public bool SomeBool { get; } public float SomeFloat { get; } private readonly string _someARelatedStuff; // Rest of class... } public class B : I { public int SomeInt { get; } public bool SomeBool { get; } public float SomeFloat { get; } private string readonly _someBRelatedStuff; private double readonly _someOtherBRelatedStuff; // Rest of class... } Sometimes I want to test equality between A and B
  • linq & distinct,实现equals & gethashcode(linq & distinct, implementing the equals & gethashcode)
    问题 所以我正在努力完成这项工作,但我似乎不知道为什么它不起作用 演示代码; namespace ConsoleApplication1 { class Program { static void Main(string[] args) { var myVar = new List<parent >(); myVar.Add(new parent() { id = "id1", blah1 = "blah1", c1 = new child() { blah2 = "blah2", blah3 = "blah3" } }); myVar.Add(new parent() { id = "id1", blah1 = "blah1", c1 = new child() { blah2 = "blah2", blah3 = "blah3" } }); var test = myVar.Distinct(); Console.ReadKey(); } } public class parent : IEquatable<parent> { public String id { get;set;} public String blah1 { get; set; } public child c1 { get; set; } public override int GetHashCode()
  • 如何限制组合框添加重复值?(How to restrict Combobox to Add Duplicate Values?)
    问题 我有一个类,用于向组合框添加值(一个用于显示,另一个用于隐藏) public class ComboBoxItem { string displayValue; string hiddenValue; //Constructor public ComboBoxItem(string displayVal, string hiddenVal) { displayValue = displayVal; hiddenValue = hiddenVal; } //Accessor public string HiddenValue { get { return hiddenValue; } } //Override ToString method public override string ToString() { return displayValue; } 使用这个类我将值添加到组合框 cmbServerNo.Items.Add(new ComboBoxItem(strIPAddress, iConnectionID.ToString())); 但我想限制重复值我使用以下方法 foreach (KeyValuePair<int, Object> ikey in m_lstConnectionID) { if (!cmbServerNo.Items.Contains