I have found this class useful so I figured that I would share it. It's main use is a quick lightweight fluent interface for creating an IEnumerable<T> in a test. The place where it excels is when we want to do something like have a nice fluent interface for adding things to another class. A while back I saw an example of this on Jeff's blog.
The particular example was:
108: [Test]
109: public void ShouldInitializeWithKeys()
110: {
111: SmartBag bag = new SmartBag().Add("key1", 2).Add("key2", 3);
112: Assert.That(bag.ContainsKey("key1"));
113: Assert.That(bag.ContainsKey("key2"));
114: }
What he had done to support this nice fluent interface for adding items was to make the SmartBag return itself from the add method (This pattern is quite common for value objects but in this case SmartBag was actually mutating itself then returning itself). I had a place or two like this in code and changed them to use the Chain<T> class by just making the class with the add support taking an IEnumerable<T> (kill two birds with one stone).
WhatEver.Add(Chain<int>.Create(1,2,3,4,5))
WhatEver.Add(
Chain<SomeObject>.Empty
.Append(New.SomeObject.WithFluentInterface)
.Append(New.SomeObject.WithFluentInterface)
.Append(New.SomeObject.WithFluentInterface)
.Append(New.SomeObject.WithFluentInterface)
.Append(New.SomeObject.WithFluentInterface)
);
Personally I find myself using the From method more to initially create them but the append can be useful as well.
This code is also an example of an immutable data structure. You can access it here http://codekeep.net/snippets/6a941ef6-88ff-4903-b0fd-7ca261ef3bd3.aspx or view it below.
One thing I have really wanted to add to it is support for adding a node of IEnumerable<T> which would then iterate that node (i.e. so you could take 5 enumerarables and combine them into 1 without actually evaluating them). Maybe I will do that tomorrow.
public class Chain : IEnumerable, IEnumerable
{
private static readonly Chain empty = new Chain(default(T), null);
public static Chain Empty
{
get { return empty; }
}
public static Chain From(T t)
{
return Empty.Append(t);
}
public static Chain From(IEnumerable _Items)
{
return Empty.Append(_Items);
}
public static Chain From(params T[] items)
{
return Empty.Append(items);
}
private readonly T item;
private readonly Chain next;
private IEnumerable GetItemsRecursive()
{
if (next != null) {
foreach (T child in next.GetItemsRecursive()) yield return child;
yield return item;
}
}
public Chain Append(T t)
{
return new Chain(t, this);
}
public Chain Append(IEnumerable _Items)
{
if (_Items == null) throw new ArgumentNullException("Items");
Chain current = this;
foreach (T cur in _Items) {
current = current.Append(cur);
}
return current;
}
public Chain Append(params T[] items)
{
return Append((IEnumerable) items);
}
private Chain(T _Item, Chain _Next)
{
item = _Item;
next = _Next;
}
public IEnumerator GetEnumerator()
{
return GetItemsRecursive().GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetItemsRecursive().GetEnumerator();
}
}
Posted
04-02-2008 1:50 AM
by
Greg