3

I have a Use Case where I want to validate a specific property in a list of objects to make sure it is unique. The basic setting can be seen in the code below.

class Program 
{
    static void Main(string[] args) 
    {
        Directory myDirectory = new Directory("Interaction Design");
        myDirectory.Books.Add(new Book("978-0-262-64037-4", "The Design of Everyday Things")); //Should be added
        myDirectory.Books.Add(new Book("978-0-262-13474-3", "Designing Interactions")); //Should be added
        myDirectory.Books.Add(new Book("978-0-262-13474-3", "Whoops, I slipped up")); //Should NOT be added
    }
}

public class Directory 
{
    public Directory(string name) 
    {
        Name = name;
    }
    public string Name { get; set; }
    public List<Book> Books { get; set; } = new List<Book>();
}

public class Book 
{
    public Book(string isbn, string title) 
    {
        Isbn = isbn;
        Title = title;
    }
    public string Title { get; set; }
    public string Isbn { get; set; }
}

Now, in the code above, adding a new Book in the List of Books should throw an exception if the ISBN number isn't unique.

I would like to extend on the .Add() method of the List and add that validation, but I'm not sure how to actually do that.

I've seen similar things, but they all assume that the Directory inherits from List and you write an overriding .Add method to the Directory - which doesn't look like a valid solution in this case.

Perhaps my general approach is backwards?

Please advice.

Asef Hossini
  • 655
  • 8
  • 11
CB Du Rietz
  • 187
  • 1
  • 10
  • see this link [How do I override List's Add method in C#?](https://stackoverflow.com/questions/580202/how-do-i-override-listts-add-method-in-c) – ali zarei Dec 07 '17 at 23:09
  • Make the books list private. Expose it with an IEnumerable getter and then an add and remove method that can do your validation and then add it to the private list or remove it? – Dave Dec 07 '17 at 23:18
  • I've seen both those questions, but never really found any solution on the validation part itself. I think the best approach is to break out the Books property to a class. – CB Du Rietz Dec 07 '17 at 23:18
  • There is a [`SortedList`](https://learn.microsoft.com/en-us/dotnet/api/system.collections.generic.sortedlist-2?view=netframework-4.7.1) built for this scenario. – Aluan Haddad Dec 07 '17 at 23:28
  • The sortedList would probably not work if I was to add more properties, right? Actually, there are more properties, I simplified the code a little. – CB Du Rietz Dec 07 '17 at 23:32

3 Answers3

4

If you want uniqueness, use a collection that gives you that: a set.

Make an IEqualityComparer<book> that considers two books to be equal if the Isbns match and use it in a HashSet<Book> that represents your unique list of books:

public class Directory 
{

    public HashSet<Book> Books { get; } 
        = new HashSet<Book>(new BookEqualityComparer());
    //...
    private class BookEqualityComparer : IEqualityComparer<Book>
    {
        public bool Equals(Book x, Book y)
        {
            if (ReferenceEquals(x, y))
                return true;

            if (ReferenceEquals(x, null) ||
                ReferenceEquals(y, null))
                return false;

            return x.Isbn == y.Isbn;
        }

        public int GetHashCode(Book obj)
            => obj.Isbn.GetHashCode();
    }
}

And you are done, you can't have any duplicate books in Books.

InBetween
  • 32,319
  • 3
  • 50
  • 90
1

One option is to create a new class and inherit from Collection<T> instead of List<T>, where you could overwrite InsertItem

e.g.

public class MyList: Collection<string>
{

    protected override void InsertItem(int index, string newItem)
    {
        DoValidation();
    }

}

called with the following call:

var myList = new MyList();
myList.Add("item1");
Julian
  • 33,915
  • 22
  • 119
  • 174
  • This seems to be the most hands-on solution, breaking out the Books property into a class of its own and manipulating that. I was hoping to avoid that, but if that's my best bet... – CB Du Rietz Dec 07 '17 at 23:15
0

Why not this?

public class Directory
{
    private List<Book> _books;

    public IEnumerable<Book> Books
    {
        {
             return _books;
        }
    }

    Public void AddBook(Book book)
    {
         //Validate 
        if(valid)
        {
            _books.Add(book);
        }
    }
    //Etc
}
Dave
  • 2,829
  • 3
  • 17
  • 44