Common Method Overload Issues

I have two methods with these signatures:

void Method<T>(T data) { } void Method<T>(IEnumerable<T> data) { } 

This is an overload of the same method to take either a single object or a list of them. If I try to pass it a List <T>, it will allow the first method, when obviosly I want the second. I have to use list.AsEnumerable () to get it to allow the second. Is there a way to force it to allow the second, regardless of whether the list is of type T [], IList <T, List <T, Collection <T, IEnumerable <T>, etc.

+7
c #
source share
6 answers

Best solution: do not go there in the first place . This is a bad design. You will notice that none of the infrastructure classes does this. The list has two methods: Add and AddRange. The first one adds one element, the second one adds a sequence of elements.

This is a bad design because you are writing a device to automatically generate errors. Consider again an example of a modified list:

 List<object> myqueries = new List<object>(); myqueries.Add(from c in customers select c.Name); myqueries.Add(from o in orders where o.Amount > 10000.00m select o); 

You expect to add two queries to the query list; if Add were overloaded to accept the sequence, then this would add the query results to the list, not the queries. You must be able to distinguish between a query and its results; they are logically completely different.

It is best to make the methods have two different names.

If you're damn tuned for this bad design, then if it hurts you when you do this, don't do it. Overload resolution is designed to find the best match. Do not try to clog the overload so that it does something even worse. Again, this is confusing and error prone. Solve the problem using a different mechanism. For example:

 static void Frob(IEnumerable ts) // not generic! { foreach(object t in ts) Frob<object>(t); } static void Frob<T>(T t) { if (t is IEnumerable) Frob((IEnumerable) t); else // otherwise, frob a single T. } 

Now, no matter what the user gives you - an array of T, an array of lists of T, regardless of whether you end up only frobbing one Ts.

But then again, this is almost certainly a bad idea. Do not do this. Two methods that have different semantics must have different names.

+8
source share

Depends if you do this:

 var list = new List<Something>(); Method<List<Something>>(list); // Will resolve to the first overload. 

Or:

 var list = new List<Something>(); Method<Something>(list); // Will resolve to the second overload. 

The reason this happens is because the compiler will choose the most specific method that can be used, so when your generic Method<T>(T data) , it compiles as Method<List<Something>>(List<Something> data) , which is more specific than IEnumerable<Something>

+1
source share

Overload resolution will try to find the best matching overload.

In case of IEnumerable<T> overload, you really need to explicitly convert or use IEnumerable<T> , since then it will be the best match.

Otherwise, a simple general overload will be considered the best match.

For more information, read "overload resolution" on Eric Lippert's blogs.

+1
source share

It is somewhat unusual to have overloads so that a method can accept either one thing or a collection of things, isn't it? Why not just

 void MethodSingle<T>(T data) { Method(new T[] { data }); } void Method<T>(IEnumerable<T> data) { } 

More clearly for both the compiler and the reader, I would suggest.

0
source share

Q:

Is there a way to make it allow the second, regardless of whether the list is of type T [], IList <'T>, List <' T>, Collection <'T>, IEnumerable <T>, etc.

T [] is not a list, but an array, so probably not.

I'm not sure if this will be useful, but you can try to create a method with restrictions

 public void Method<U,T> (U date) where U : IList<T> { /* ... */ } 
0
source share

Why not expand the method this way:

 void Method<T>(T data) { var enumerable = data as IEnumerable<T>; if(enumerable != null) { Method(enumerable); return; } ... } 
-one
source share

All Articles