【问题标题】:How to Properly Implement Equals with Collections如何使用集合正确实现等于
【发布时间】:2016-06-24 11:12:50
【问题描述】:

我有以下课程,其中包含 MSDN 记录的 2 个相等方法。

public class Book
{

public string bookTitle {get; private set;}
public IReadOnlyCollection<Author> authors {get; private set;}
public string ISBN {get; private set;}
public int numberofpages {get; private set; }
public string Genre {get; private set; }

public Book(string bookTitle, IReadOnlyCollection<Author> authors, string ISBN, int numberofpages, string genre)
{
    if(string.IsNullOrWhiteSpace(bookTitle)){
        throw new ArgumentNullException("Book Must Have Title!");
    }
    this.bookTitle = bookTitle;

    if(authors.Count < 0){
        throw new ArgumentNullException("You must provide at least one author!");
    }
    this.authors = new ReadOnlyCollection<Author>(new List<Author>(authors));

    if(String.IsNullOrWhiteSpace(ISBN)){
        throw new ArgumentNullException("A Book Has to have an ISBN number. Check online or the back cover");
    }
    this.ISBN = ISBN;
    if(numberofpages <= 0){
        throw new ArgumentNullException("A Book has more than one page!");
    }
    this.numberofpages = numberofpages;
    if(String.IsNullOrWhiteSpace(genre)){
        throw new ArgumentNullException("A Book has a genre. Find it and input it");
    }
    this.Genre = genre;
}


public override bool Equals(Object obj)
{
    if (obj == null)
    {
        return false;
    }

    Book p = obj as Book;
    if ((System.Object)p == null)
    {
        return false;
    }
    return (bookTitle == p.bookTitle) && (authors == p.authors) && (numberofpages == p.numberofpages) && (ISBN == p.ISBN) && (Genre == p.Genre);
}

public bool Equals(Book p)
{
    if ((object)p == null)
    {
        return false;
    }

    return (bookTitle == p.bookTitle) && (authors == p.authors) && (numberofpages == p.numberofpages) && (ISBN == p.ISBN) && (Genre == p.Genre);
}


   public class Author
   {
     public int ID {get; private set;}
     public string firstname {get; private set;}
     public string lastname {get; private set;}

     public(int id, string firstname, string lastname)
     {
        this.ID = id;
        this.firstname = firstname;
        this.lastname = lastname;
     }

     //Rest of code here: just toString method

}

我的问题:

这两种方法都将评估为 false,因为我在构造函数中分配作者之前创建了一个新列表:

this.authors = new ReadOnlyCollection<Author>(new List<Author>(authors)); 

我这样做是为了让用户无法在课堂外更改ReadOnlyCollection。所做的任何更改都将在该集合的副本上。考虑到这一点,鉴于我创建了一个新列表,我如何让我的 Equals to 方法正常工作?

【问题讨论】:

  • 您必须比较作者列表项。在每个索引处对作者进行排序和比较,直到它们不相等或到达列表末尾。此外,Book 和 Author 都应实施 IEquatable 以防止出现问题并保持理智。
  • @MaxSorin - 你能告诉我怎么做吗?
  • 答案提供了代码和实现的接口

标签: c# collections equals


【解决方案1】:

您的 Book 类可以/应该实现 IComparableIEquatable。您可能还希望将您的收藏保持排序Sort ObservableCollection<string> C#。如果没有更多信息,很难推荐一个坚如磐石的答案,但如果您查看我提供的链接/建议,您的项目可能会取得良好进展。

【讨论】:

    【解决方案2】:
    using System;
    using System.Collections.Generic;
    using System.Collections.ObjectModel;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace TestArea.Other
    {
        public class Author : IComparable<Author>
        {
            public string Name { get; set; }
    
            public int CompareTo(Author other) => this.Name.CompareTo(other.Name);
        }
    
        public class Authors :  ReadOnlyCollection<Author>, IEquatable<Authors>
        {
            public Authors(IList<Author> list) : base(list)
            {
    
            }
    
            public bool Equals(Authors other)
            {
                //reference equal 
                if (other == this)
                {
                    return true;
                }
    
                //No need to iterate over authors
                if (other == null || other.Count != this.Count)
                {
                    return false;
                }
    
                var thisSorted = this.ToArray();
                var otherSorted = other.ToArray();
                Array.Sort(thisSorted);
                Array.Sort(otherSorted );
    
                for (int i = 0; i < thisSorted.Length; i++)
                {
                    if (thisSorted[i].CompareTo(otherSorted[i]) != 0)
                    {
                        return false;
                    }
                }
    
                return true;
            }
        }
    
        public class Book : IEquatable<Book>
        {
    
            public string bookTitle { get; private set; }
            public Authors authors { get; private set; }
            public string ISBN { get; private set; }
            public int numberofpages { get; private set; }
            public string Genre { get; private set; }
    
            //Made Authors parameter as simplified as it could be
            public Book(string bookTitle, IEnumerable<Author> authors, string ISBN, int numberofpages, string genre)
            {
                var authorList = authors.ToList();
                if (string.IsNullOrWhiteSpace(bookTitle))
                {
                    throw new ArgumentNullException("Book Must Have Title!");
                }
                this.bookTitle = bookTitle;
    
                if (authorList.Count() < 0)
                {
                    throw new ArgumentNullException("You must provide at least one author!");
                }
                this.authors = new Authors(new List<Author>(authorList));
    
                if (String.IsNullOrWhiteSpace(ISBN))
                {
                    throw new ArgumentNullException("A Book Has to have an ISBN number. Check online or the back cover");
                }
                this.ISBN = ISBN;
                if (numberofpages <= 0)
                {
                    throw new ArgumentNullException("A Book has more than one page!");
                }
                this.numberofpages = numberofpages;
                if (String.IsNullOrWhiteSpace(genre))
                {
                    throw new ArgumentNullException("A Book has a genre. Find it and input it");
                }
                this.Genre = genre;
            }
    
    
            public override bool Equals(Object obj)
            {
                if (obj == null)
                {
                    return false;
                }
    
                Book p = obj as Book;
                if ((System.Object) p == null)
                {
                    return false;
                }
                return (bookTitle == p.bookTitle) && (authors.Equals( p.authors)) && (numberofpages == p.numberofpages) &&
                       (ISBN == p.ISBN) && (Genre == p.Genre);
            }
    
            public bool Equals(Book p)
            {
                if ((object) p == null)
                {
                    return false;
                }
    
                return (bookTitle == p.bookTitle) && (authors.Equals( p.authors)) && (numberofpages == p.numberofpages) &&
                       (ISBN == p.ISBN) && (Genre == p.Genre);
            }
        }
    
    }
    

    通用 IEnumerable Equality 方法:

     public static class IEnumerableExtensions
        {
            public static bool EqualTo<T>(this IEnumerable<T> enumerable, IEnumerable<T> other)
            {
                //reference equal 
                if (other == enumerable)
                {
                    return true;
                }
    
                if (other == null)
                {
                    return false;
                }
    
                var enumerableSorted = enumerable.ToArray();
                var otherSorted = other.ToArray();
    
                //No need to iterate over items if lengths are not equal
                if (otherSorted.Length != enumerableSorted.Length)
                {
                    return false;
                }
    
                Array.Sort(enumerableSorted);
                Array.Sort(otherSorted);
    
                return !enumerableSorted.Where((t, i) => t.Equals(otherSorted[i])).Any();
            }
        }
    

    用法:

    public override bool Equals(Object obj)
    {
        if (obj == null)
        {
            return false;
        }
    
        Book otherBook = obj as Book;
        if ((System.Object) otherBook == null)
        {
            return false;
        }
    
        return (bookTitle == otherBook.bookTitle) && 
            otherBook.authors.EqualTo(this.authors) && 
            (numberofpages == otherBook.numberofpages) &&
            (ISBN == otherBook.ISBN) && 
            (Genre == otherBook.Genre);
    }
    

    【讨论】:

    • 非常感谢,但是,作者没有这么复杂。它只是一个具有 int author ID、字符串 authorFirstname、字符串 authorLastName 的类。
    • Authors 只是允许我在一个语句中将列表相互比较。您可以创建自己的方法来比较 ReadOnlyCollections&lt;T&gt; 中的项目
    • 我更新了我的代码以包含我的 Authors 类,请看一下,如果您可以更改您的代码,以便我了解该怎么做。向下滚动它在底部
    • 拜托,我正在学习,你能告诉我如何创建自己的方法来比较 ReadOnlyCollections 中的项目吗?
    • 为什么这还不足以让 equals 方法工作? msdn.microsoft.com/en-us/library/ms173147%28v=vs.90%29.aspx
    猜你喜欢
    • 2018-02-13
    • 1970-01-01
    • 2021-06-26
    • 1970-01-01
    • 2020-09-03
    • 1970-01-01
    • 1970-01-01
    • 2019-09-05
    • 2011-08-05
    相关资源
    最近更新 更多