4

Example: I would like to have the Add method of ICollection of a custom collection class to implement method chaining and fluent languages so I can do this:

randomObject.Add("I").Add("Can").Add("Chain").Add("This").

I can think of a few options but they are messy and involves wrapping ICollection in another interface and so forth.

Marc Gravell
  • 1,026,079
  • 266
  • 2,566
  • 2,900
danmine
  • 11,325
  • 17
  • 55
  • 75

6 Answers6

11

While fluent is nice, I'd be more interested in adding an AddRange (or two):

public static void AddRange<T>(this ICollection<T> collection,
    params T[] items)
{
    if(collection == null) throw new ArgumentNullException("collection");
    if(items == null) throw new ArgumentNullException("items");
    for(int i = 0 ; i < items.Length; i++) {
        collection.Add(items[i]);
    }
}
public static void AddRange<T>(this ICollection<T> collection,
    IEnumerable<T> items)
{
    if (collection == null) throw new ArgumentNullException("collection");
    if (items == null) throw new ArgumentNullException("items");
    foreach(T item in items) {
        collection.Add(item);
    }
}

The params T[] approach allows AddRange(1,2,3,4,5) etc, and the IEnumerable<T> allows use with things like LINQ queries.

If you want to use a fluent API, you can also write Append as an extension method in C# 3.0 that preserves the original list type, by appropriate use of generic constraints:

    public static TList Append<TList, TValue>(
        this TList list, TValue item) where TList : ICollection<TValue>
    {
        if(list == null) throw new ArgumentNullException("list");
        list.Add(item);
        return list;
    }
    ...
    List<int> list = new List<int>().Append(1).Append(2).Append(3);

(note it returns List<int>)

Marc Gravell
  • 1,026,079
  • 266
  • 2,566
  • 2,900
5

You could also use an extension method that would be usable with any ICollection<T> and save you from writing your own collection class:

public static ICollection<T> ChainAdd<T>(this ICollection<T> collection, T item)
{
  collection.Add(item);
  return collection;
}
Curtis Buys
  • 2,341
  • 1
  • 17
  • 13
3

You would need to return void from Add as that is how it is set out in ICollection. That rules out the chained Add Method taking just one parameter, I believe.

Not quite what you want but you could add something like this to your custom collection type.

public CustomCollectionType Append(string toAdd)
{
  this.Add(string toAdd);
  return this;
}

Then you could do:

customCollection.Append("This").Append("Does").Append("Chain");

Hope that helps,

Dan

Daniel Elliott
  • 22,647
  • 10
  • 64
  • 82
  • +1 for using Append instead of Add. All the places I can remmember of have Add return void or the item. Never the collection. Having Add return the collection kind of breaks a convention. – Alfred Myers Aug 28 '09 at 23:01
2

Another option would be to use the C# collection initializer:

var list = new YourList<String>()
    {
         "Hello",
         "World",
         "etc..."
    };
Stephanvs
  • 723
  • 7
  • 19
0

You can hide ICollection.Add method in your custom collection class and return this.

public class MyList<T>:List<T>
{
  public new MyList<T> Add(T item)
  {
     (this as ICollection<T>).Add(item);
     return this;
  }
}

then you can add item with chained Add calls:

MyList<string> strList = new MyList<string>();
strList.Add("Hello").Add(" ").Add("World!");
Mehmet Aras
  • 5,284
  • 1
  • 25
  • 32
  • Is it still possible to implement ICollection in the custom collection class in this manner? – Daniel Elliott Aug 28 '09 at 22:49
  • If you implement ICollection implicitly, I don't think so because you would then have two Add methods with the same signature in the same class. They will only differ in return type but the compiler does not consider return type to differentiate between method overloads. However, if you implement ICollection explicitly, then both Add methods can exist together. – Mehmet Aras Aug 28 '09 at 22:58
  • I haven't downvoted you, but I guess it would be due to the method-hiding advice. It would make for a really confusing class to use, given that it would behave differently depending on it's variable type. – Noon Silk Aug 29 '09 at 07:57
  • Why would it be confusing? You expect an Add method on a collection and it is there. It takes the same parameter that you come to expect. The only difference is its return type and it allows exactly what the poster wants to do. To me, confusing, from an api stand point, would be an extension method that provides the same functionality as Add but differs only in return type. Tell me when you're using this collection with an extension method and you see Add and Append, would you not stop and ask yourself what the difference between the two is? I would and that's confusing. – Mehmet Aras Aug 29 '09 at 12:43
0

No offense, but maybe you would prefer VB.NET

It's more conducive to 'natural language' programming than C# is.

In VB.NET you have the "with" construct that will let you do:

With myCollection
    .Add("Hello")
    .Add("There")
    .Add("My")
    .Add("Name")
    .Add("Is")
    .Add("Silky")
    .Sort()
End With
Noon Silk
  • 54,084
  • 6
  • 88
  • 105