views:

461

answers:

6

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.

+3  A: 

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
+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
A: 

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
Is it still possible to implement ICollection in the custom collection class in this manner?
Daniel Elliott
If you implement ICollection<T> 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<T> explicitly, then both Add methods can exist together.
Mehmet Aras
It will be nice to know the reason for downvotes.
Mehmet Aras
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
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
+2  A: 

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

var list = new YourList<String>()
    {
         "Hello",
         "World",
         "etc..."
    };
Stephan
+5  A: 

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;
}
itsmecurtis
+6  A: 

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
I'm confused... why isn't this the top-rated and accepted answer yet?!
Daniel Earwicker
A: 

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