如何正确实现与集合的等价

时间:2016-03-09 20:56:40

标签: c# collections equals

我有以下类,使用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,因为我在构造函数中指定作者之前创建了一个新的List:

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

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

2 个答案:

答案 0 :(得分:1)

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);
}

答案 1 :(得分:0)

您的图书课程可以/应该实施IComparableIEquatable。您可能还希望将收藏集分类为Sort ObservableCollection<string> C#。如果没有更多信息,很难推荐一个坚如磐石的答案,但如果你查看我所做的链接/建议,你可能会在你的项目上取得很好的进展。