2

我有以下课程:

 public class MyDocuments
    {
        public DateTime registeredDate;
        public string version;
        public List<Document> registeredDocuments;
    }

    public class Document
    {
        public string name;
        public List<File> registeredFiles;
    }

    public class File
    {
        public string name;
        public string content;
    }

我有一个 MyDocuments 实例,其中包含多个文档List<Document> registeredDocument。我从用户那里得到一个新List<Document>的。

如何验证列表中不存在新对象?我想按价值比较而不是参考。

我正在考虑使用 HashSet 而不是 List。这是正确的方法吗?

4

5 回答 5

2

如何进行相等比较?

每当 BCL 类想要在某种类型的对象之间执行相等性检查时T,它们会通过调用IEqualityComparer<T>. 为了获得这样的实现,框架看起来EqualityComparer<T>.Default.

如文档中所述,此属性会产生IEqualityComparer<T>如下内容:

Default property检查类型 T 是否实现了 System.IEquatable<T>接口,如果是,则返回 EqualityComparer<T>使用该实现的一个。否则,它返回一个EqualityComparer<T>使用 Object.EqualsObject.GetHashCode提供的覆盖的T

我有哪些选择?

因此,一般而言,要规定应如何执行相等比较,您可以:

  1. 显式提供IEqualityComparer<T>执行相等检查的类或方法的实现。此选项在 中不是很明显List<T>,但许多 LINQ 方法(例如Contains)确实支持它。
  2. 让你的班级实现IEquatable<T>. 这将EqualityComparer<T>.Default使用这个实现,并且只要有一种明显的“自然”方式来比较 type 的对象,它就是一个不错的选择T
  3. 覆盖object.GetHashCode而不object.Equals实施IEqualityComparer<T>. 但是,这只是#2 的劣质版本,应始终避免使用 AFAIK。

选择哪个选项?

一个好的经验法则是:如果有一种明显且自然的方式来比较 class 的对象T,请考虑实现它IEquatable<T>;这将确保在整个框架中使用您的比较逻辑,而无需任何额外的参与。如果没有明显的候选者,或者如果您想以不同于默认方式的方式进行比较,请实现您自己的IEqualityComparer<T>并将实现作为参数传递给需要执行相等检查的类或方法。

于 2012-11-26T19:38:46.577 回答
1

您将需要实现该Equals()方法,可能GetHashCode()还需要实现。有关示例,请参见此答案。

于 2012-11-26T19:12:13.807 回答
1

你应该实施IEquatable<T>.

当您在您的自定义对象上实现此接口时,任何相等性检查(例如 Contains、IndexOf)都会使用您的对象实现自动完成。

于 2012-11-26T19:12:51.657 回答
0

覆盖object.Equals方法。

这是直接来自文档的示例

public class Person
{
   private string idNumber;
   private string personName;

   public Person(string name, string id)
   {
      this.personName = name;
      this.idNumber = id;
   }

   public override bool Equals(Object obj)
   {
      Person personObj = obj as Person; 
      if (personObj == null)
         return false;
      else 
         return idNumber.Equals(personObj.idNumber);
   }

   public override int GetHashCode()
   {
      return this.idNumber.GetHashCode(); 
   }
}

Equals方法返回一个布尔值,它是否obj等于this

于 2012-11-26T19:11:46.237 回答
0

在顶层是这样的,在子层继续下去:

public class MyDocuments
{
    public DateTime registeredDate;
    public string version;
    public HashSet<Document> registeredDocuments;
    public override bool Equals(Object o)
    {
        if( !(o is MyDocuments) ) return false;
        MyDocuments that = (MyDocuments)o;
        if( !String.Equals(this.version, that.version) ) return false;
        if( this.registeredDocuments.Count != that.registeredDocuments.Count ) return false;
        // assuming registeredDate doesn't matter for equality...
        foreach( Document d in this.registeredDocuments )
            if( !that.registeredDocuments.Contains(d) )
                return false;
        return true;
    }
    public override int GetHashCode()
    {
        int ret = version.GetHashCode();
        foreach (Document d in this.registeredDocuments)
            ret ^= d.GetHashCode(); // xor isn't great, but better than nothing.
        return ret;
    }
}

注意:如果属性可以感知变化,缓存可能对 HashCode 值有用。

于 2012-11-26T19:50:04.003 回答