thoughts on coding

August 11, 2010

IEnumarable with a Count = IEnumerableList

Filed under: .NET, Uncategorized — Frantisek @ 1:07 pm

I do Domain-Drive-Design (DDD) and one of the golder rules practically says that the domain model shouldn’t expose more necessary.

Example:

    1 public class Item

    2 {

    3     public IList<Bid> Bids

    4     {

    5         get; private set; }

    6 

    7     public Item()

    8     {

    9         Bids = new List<Bid>();

   10     }

   11 }

   12 

   13 public class Bid

   14 {

   15 }

The class Item has collection of the Bid(s). So Item can expose property IList Bids {get;}. The problem is that in case Bid has a reference to Item then it’s possible that that Bid1 whose parent item is Item1 is added to Item2. The designer of the domain model enable us to do it. This is violation of the domain model rules.

Solution: we should add method AddBid(Bid bid) {} to the class Item and change the Item’s property Bids to the following IEnumerable Bids {get;}

Fine, but what to do in case there is a logic which would like to know how many bids some item has. IEnumerable doesn’t expose such property. For such cases I create my IEnumerableList.

    1 public interface IEnumerableList<T> : IEnumerable<T>

    2 {

    3     /// <summary>

    4     /// Gets the <see cref="T"/> at the specified index.

    5     /// </summary>

    6     /// <value></value>

    7     T this[int index] { get; }

    8 

    9     /// <summary>

   10     /// Gets the count.

   11     /// </summary>

   12     /// <value>The count.</value>

   13     int Count { get; }

   14 }

and I also created the List implementation called EnumerableList:

    1 public class EnumerableList<T> : IEnumerableList<T>

    2 {

    3     private readonly IList<T> underlyingList;

    4 

    5     /// <summary>

    6     /// Initializes a new instance of the <see cref="EnumerableList&lt;T&gt;"/> class.

    7     /// </summary>

    8     /// <param name="list">The list.</param>

    9     public EnumerableList(IList<T> list)

   10     {

   11         underlyingList = list;

   12     }

   13 

   14     #region Implementation of IEnumerable

   15 

   16     /// <summary>

   17     /// Returns an enumerator that iterates through the collection.

   18     /// </summary>

   19     /// <returns>

   20     /// A <see cref="T:System.Collections.Generic.IEnumerator`1"/> that can be used to iterate through the collection.

   21     /// </returns>

   22     /// <filterpriority>1</filterpriority>

   23     public IEnumerator<T> GetEnumerator()

   24     {

   25         return underlyingList.GetEnumerator();

   26     }

   27 

   28     /// <summary>

   29     /// Returns an enumerator that iterates through a collection.

   30     /// </summary>

   31     /// <returns>

   32     /// An <see cref="T:System.Collections.IEnumerator"/> object that can be used to iterate through the collection.

   33     /// </returns>

   34     /// <filterpriority>2</filterpriority>

   35     IEnumerator IEnumerable.GetEnumerator()

   36     {

   37         return underlyingList.GetEnumerator();

   38     }

   39 

   40     #endregion

   41 

   42     #region Implementation of IEnumerableList<T>

   43 

   44     /// <summary>

   45     /// Gets the <see cref="T"/> at the specified index.

   46     /// </summary>

   47     /// <value></value>

   48     public T this[int index]

   49     {

   50         get { return underlyingList[index]; }

   51     }

   52 

   53     /// <summary>

   54     /// Gets the count.

   55     /// </summary>

   56     /// <value>The count.</value>

   57     public int Count

   58     {

   59         get { return underlyingList.Count; }

   60     }

   61 

   62     #endregion

   63 }

And the final solution looks like the following:

    1 public class Item

    2    {

    3        public IEnumerableList<Bid> Bids

    4        {

    5            get

    6            {

    7                return new EnumerableList<Bid>(_bids);

    8            }

    9        }

   10        private IList<Bid> _bids;

   11 

   12        public Item()

   13        {

   14            _bids = new List<Bid>();

   15        }

   16 

   17        public void AddBid(Bid bid)

   18        {

   19            _bids.Add(bid);

   20        }

   21    }

   22 

   23    public class Bid

   24    {

   25    }

In this case the domain model doesn’t allow me to do prohibited action.

Original article was published at www.Catarsa.com

Advertisements

2 Comments »

  1. Hi Frantisek,

    why don’t you use the ReadonlyCollection here?

    Cheers
    Marc

    Comment by Marc — December 6, 2010 @ 9:11 pm

    • Hi Marc,

      the reason is that the class exposes the functions which throws the exceptions and dont make sense for that purpose. I.e. if you have a class where you want to expose the read-only access collection (I use like interface, so I use ICollection or IList) without writing any comments for the getter to inform the consumer of your class that it’s ReadOnlyCollection.

      ICollection doesnt expose any indexer, any Count only the Linq extension methods.
      IList exposes teh functionality which doesn’t make sense with ReadOnly case.

      If you have better solution, please, send me the example.
      F

      Comment by Frantisek — December 6, 2010 @ 9:31 pm


RSS feed for comments on this post. TrackBack URI

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Create a free website or blog at WordPress.com.

%d bloggers like this: