2015-04-09

Proper collection implementation in .net

Most people I've worked with that needed a collection of some sort have implemented the collection by inheriting from one of the standard collection classes. This is however typically not the right thing to do since you expose more functionality than you really want in many cases.

Sure by inheriting from a collection base class you don't have to write a lot of code, but then it also means you expose more functions that you really want the user of your collection class to use.

Instead I recommend that you create your own collection classes by implementing the interfaces you actually want to expose and keep an internal private member to store your collection data. This way you know what you are really exposing and your object's interface will be less cluttered since it will only have the interfaces you actually want to expose.

But there is more... There is another trick I rarely see people use. Probably because people don't know about it. That is if a class implements IEnumerable and have an Add method then you can create that object using an object initializer. One of the more common examples that you might have seen is creating a small dictionary to use:
var d = new Dictionary<string, int> { { "a", 47 }, { "b", 11 } };
But there is more! The way the collection initializer works is that it will use any Add method that has arguments matching the collection initializer. What this means might want to make you shower because it can sure feel dirty but it can also be used to achieve some interesting syntax in your code. In the following example it is not really a collection and I hide that fact by explicitly implementing the interface. Yet I have access to some pretty interesting syntax.
   1:  class MyString : IEnumerable
   2:  {
   3:      private StringBuilder r = new StringBuilder();
   4:   
   5:      public void Add(string s, int v)
   6:      {
   7:          for (int i=0; i < v; i++)
   8:              this.Add(s);
   9:      }
  10:      
  11:      public void Add(string s)
  12:      {
  13:          this.r.Append(s);
  14:      }
  15:      
  16:      IEnumerator IEnumerable.GetEnumerator()
  17:      {
  18:          throw new NotImplementedException();
  19:      }
  20:      
  21:      public override string ToString()
  22:      {
  23:          return this.r.ToString();
  24:      }
  25:  }
  26:   
  27:  var s = new MyString { { "Hello ", 2 }, { "World" }, { "!", 5 } };
Have you used the collection initializer to do something cool in your code? Let me know!

No comments:

Post a Comment