Enforce right method overload to be called - c#

I have two methods with the following signatures:
public void DoSomething<T>(T value) { ... }
public void DoSomething<T>(IEnumerable<T> value) { ... }
I'm trying to call the second one like this:
DoSomething(new[] { "Pizza", "Chicken", "Cheese" });
It still jumps into the first one.
How can I enforce that it will enter the second method instead? For example by using a where clause for the generic parameter?
Edit:
To be more precise: Why does it not work, even if I am more specific and change the overloads to something like this, which will result in an compile error when trying to call the method like shown above:
public void DoSomething<T>(T value) where T : IComparable { ... }
public void DoSomething<T>(IEnumerable<T> value) where T : IComparable { ... }

You can explicitly cast it to IEnumerable<T> reference at first place after initialization and then pass in to the method as parameter like following, so that it resolves to more specific overload which would be IEnumerable<T> not T:
DoSomething(new[] { "Pizza", "Chicken", "Cheese" } as IEnumerable<string>);
or this can also be done:
IEnumerable<string> foods = new[] { "Pizza", "Chicken", "Cheese" };
DoSomething(foods);
The problem is when you do not cast it to IEnumerable<T>, it's type at compile time is String[], so it would resolve to the overload which take T as input parameter.
So at calling time, your code actually is compile like:
DoSomething<String[]>(foods);
So it calls the first overload instead of the second one.
Another solution to this is to specify the generic type parameter yourself explicitly instead of compiler to resolve itself like:
DoSomething<String>(foods);
Refer to the following demo fiddle i just created to explain it:
Demo Fiddle
Edit:
As some people are suggesting the better would be to change the method name to be obvious enough that one can understand for what kind of types it can process, though the work around that i mention would work.
Hope it Helps!

When there are multiple applicable overloads of a method there are several different factors that are used to determine which one is "better". One of those factors is how "close" each of the parameters are to the types in the method signature. string[] is an IEnumerable<string>, so it's valid in that parameter slot, but string[] is closer to string[] (an exact match is as "close" as it gets) than it is to IEnumerable<string>, so the first overload is "closer" than the second.
So if you change the compile time type of your second parameter to exactly IEnumerable, then both overloads will be exactly the same on the "closeness" scale. Since that's the same, it goes on to another "betterness" tiebreaker, which is that non-generic methods are "better" than generic methods, so you end up calling the overload that you want.
As far as how to change the compile time type of that expression to IEnumerable<string>, the most convenient way would be AsEnumerable:
DoSomething(new[] { "Pizza", "Chicken", "Cheese" }.AsEnumerable());

As explained in #Servy's excellent answer, the compiler will choose the best matching type for overloaded methods.
By changing the generic function to use object instead, you cause anything that is an IEnumerable<> to match that function best.
public void DoSomething(object value) { ... }
public void DoSomething<T>(IEnumerable<T> value) { ... }
I think it may be theoretically possible that downcasting value to object could cause a performance issue versus the generic method, but since DoSomething doesn't return the value or take another parameter of matching type T, the use of object is restricted to the body of DoSomething and will allow all uses that are legal for T.

Because T accepts all the types and string[] is not an IEnumerable directly. It is derived from it.
DoSomething(new[] { "Pizza", "Chicken", "Cheese" }.AsEnumerable());

Related

Difference between Task.FromResult<TResult> vs Task.FromResult? [duplicate]

So, I ran across an answer by Servy ( https://stackoverflow.com/a/15098242/496680 ) and some of his code does this:
public static int BinarySearch<TSource, TKey>(...)
for an extension method, but he calls it like this:
arr.BinarySearch(...)
I asked around and somebody metioned that its an implied generic type parameter.
I googled them but found no information on them.
I understand how generics work but I'm failing to understand how/when to use these.
Why does servy use them in his extention method?
Is there a more official name for these that I can search for?
Well, you left out the most important part that makes it all work. The type parameters can be inferred by the actual object parameters passed in.
For instance:
static class Extensions {
internal static IEnumerable<U> Test<T, U>(
this IEnumerable<T> items,
Func<T, U> converter) {
foreach (T item in items) {
yield return converter(item);
}
}
}
This extension method works on any IEnumerable class and will convert each item in the enumeration to another type based on the converter you provided. This is standard generics.
Now, there are many ways to call this method:
IEnumerable<int> values = Enumerable.Range<int>(1, 10);
Func<int, string> converter = i => i.ToString("0.00");
// Variation 1, explicit calling
IEnumerable<string> results1 = Extensions.Test<int, string>(values, converter);
// Variation 2, explicit calling with type inference
IEnumerable<string> results2 = Extensions.Test(values, converter);
// Variation 3, extension method calling, still providing explicit types
IEnumerable<string> results3 = values.Test<int, string>(converter);
// Variation 4, extension method with type inference
IEnumerable<string> results4 = values.Test(converter);
All four variations call the same method and return the same result. Type inference works by looking at the parameters passed and automatically inferring their types based on what's being provided. In our examples above, it's able to determine that type T is of type int because we passed in an IEnumerable<int> into the parameter for IEnumerable<T>. It is also able to infer that type U is of type string because we passed in a Func matching the initial type of T with int and returning a string. So the Func<T, U> is filled in with our converter function of Func<int, string>.
From the inference above, it's a standard generic method at that point. Type inference and extension methods are nothing more than convenience/syntactic sugar. In fact, if you decompile the output you can see that extension methods are replaced with static calls and are usually defined with the type parameters explicitly filled out. (This varies based on your decompiler and the set options).
He uses a generic method in this case because it allows his method to work with any type contained within a Collection<T>. The generic method makes this very flexible, and usable for any type. He uses the type inferrence when calling the method because it simplifies the code at the call site.
The automatic handling is called Type Inferrence, and is covered, in detail, in the C# Language Specification, section 7.5.2: Type Inferrence. If you want to understand it in detail, I would recommend downloading the C# language specification.
The term I usually hear is 'type inference'.

Strange behavior from function overload resolution in c# with generics [duplicate]

The following program does not compile, because in the line with the error, the compiler chooses the method with a single T parameter as the resolution, which fails because the List<T> does not fit the generic constraints of a single T. The compiler does not recognize that there is another method that could be used. If I remove the single-T method, the compiler will correctly find the method for many objects.
I've read two blog posts about generic method resolution, one from JonSkeet here and another from Eric Lippert here, but I could not find an explanation or a way to solve my problem.
Obviously, having two methods with different names would work, but I like the fact that you have a single method for those cases.
namespace Test
{
using System.Collections.Generic;
public interface SomeInterface { }
public class SomeImplementation : SomeInterface { }
public static class ExtensionMethods
{
// comment out this line, to make the compiler chose the right method on the line that throws an error below
public static void Method<T>(this T parameter) where T : SomeInterface { }
public static void Method<T>(this IEnumerable<T> parameter) where T : SomeInterface { }
}
class Program
{
static void Main()
{
var instance = new SomeImplementation();
var instances = new List<SomeImplementation>();
// works
instance.Method();
// Error 1 The type 'System.Collections.Generic.List<Test.SomeImplementation>'
// cannot be used as type parameter 'T' in the generic type or method
// 'Test.ExtensionMethods.Method<T>(T)'. There is no implicit reference conversion
// from 'System.Collections.Generic.List<Test.SomeImplementation>' to 'Test.SomeInterface'.
instances.Method();
// works
(instances as IEnumerable<SomeImplementation>).Method();
}
}
}
Method resolution says that closer is better. See the blog post for exact rules.
What does the closer mean? Compiler will see if it can find exact match, if it can't find for some reason it will find next possible compatible methods and so forth.
Let's first make that method compile by removing the SomeInterface constraint.
public static class ExtensionMethods
{
public static void Method<T>(this T parameter) //where T : SomeInterface
{ }
public static void Method<T>(this IEnumerable<T> parameter) //where T : SomeInterface
{ }
}
Now compiler is happy to compile, and do note that both method calls Goes to Method(T) rather than Method(IEnumerable<T>). Why is that?
Because Method(T) is closer in the sense that can take any type as the parameter and also it doesn't require any conversion.
Why is Method(IEnumerable<T>) not closer?
It is because you have the compile time type of the variable as List<T>, so it needs a reference conversion from List<T> to IEnumerable<T>. Which is closer but far from doing no conversions at all.
Back to your question.
Why instances.Method(); doesn't compile?
Again, as said earlier to use Method(IEnumerable<T>) we need some reference conversion, so obviously that's not closer. Now we're left with only one method which is very closer is Method<T>. But the problem is you have constrained it with SomeInterface and clearly List<SomeImplementation>() is not convertible to SomeInterface.
The problem is (am guessing) checking for generic constraints happens after the compiler chooses the closer overload. That invalidates the chosen best overload in this case.
You could easily fix it by changing the static type of the variable to IEnumerable<SomeImplementation> that will work and now you know why.
IEnumerable<SomeImplementation> instances = new List<SomeImplementation>();
Have you tried implementing the first one without generics, as it should behave the same:
public static void Method(this SomeInterface parameter) { /*...*/ }
Or, as Dmitry suggested, by calling the second one the following way:
instances.Method<SomeImplementation>();
But here you need to add the <SomeImplementation> to every call...
While I know you dont want it, I think you should really re-think if method names should be the same. I cannot see how the same name can act on an instance, and collection of such instances. For eg, if your method name is Shoot for T, then the other method should sound like ShootThemAll or something similar.
Or else you should make your assignment slightly different:
IEnumerable<SomeImplementation> instances = new List<SomeImplementation>();
instances.Method(); //now this should work
As a last option, as Dimitry says in comments you have to explicitly specify the type argument.
instances.Method<SomeImplementation>();

Different overload method is chosen, depending from where it's called with a null parameter

I have a class with an overloaded Format method.
class FormatStuff
{
public static string Format(object arg)
=> HandleObjectStuff();
public static string Format(IEnumerable<object> args)
=> HandleListStuff();
}
Now, when I call
FormatStuff.Format(null);
I end up in the second overload with the IEnumerable parameter.
But in my case, I call the method from within a function like this:
public static string DoStuff(IEnumerable<int> intnumerable)
{
StringBuilder sb = new StringBuilder();
sb.Append(FormatStuff.Format(intnumerable));
return sb.ToString();
}
When I call this function like
DoStuff(null);
I end up in the first overload with the single object parameter, even though in both cases null is passed as the parameter.
Why is this and what can I do to end up in the second overload that matches the type of the DoStuff-parameter?
Edit:
The question has been marked as a possible duplicate of this one. I don't think that's entirely the case, because the salient point that helped me understand my problem was, that an IEnumerable<int> is not an IEnumerable<object>.
In general that means, that one cannot expect an IEnumerable of any type to be an IEnumerable of object, which I did not know.
This conclusion is not drawn in the mentioned post.
Which overload to call (binding) is statically fixed for each invocation expression at compile-time (unless you use type dynamic at compile-time). Just because the expression you use for argument happens to evaluate to another type when the program runs, the overload will not magically change.
Examples:
FormatStuff.Format(null);
The compile-time type does not exist (null), but since there is an implicit conversion from the null literal to object and an implicit conversion from null to IEnumerable<object> as well, both overloads are candidates. In that case the overload with IEnumerable<object> is preferred because it is more specific.
FormatStuff.Format((object)null);
In this case the compile-time type of the expression is object, so only one overload applies, and that is used.
IEnumerable<int> intnumerable
// ...
FormatStuff.Format(intnumerable);
In the above case the compile-time type of what you pass is IEnumerable<int>. Here int is a value-type. An IEnumerable<int> is not an IEnumerable<object> at compile-time. This is fixed at compile-time; it does not matter whether intnumerable happens to be null at run-time, and if non-null, it does not matter what the actual type (some concrete class or struct implementing IEnumerable<int>) is at run-time.
IEnumerable<string> strEnumerable
// ...
FormatStuff.Format(strEnumerable);
Finally, in this case, since string is a reference type, the compile-time covariance of IEnumerable<out T> applies. So an IEnumerable<string> is an IEnumerable<object>. Therefore both overloads apply, and the most specific one is preferred.
To achieve what you want, your method must be able to distinguish between the two method calls.
When you pass null the Format() method doesn't know if your null is an object or IEnumerable<object> since both are of type object.
To solve your issue you can do one of the following:
1 Change the second method as Format(IEnumerable<int> args)
OR
2 Change the type signature of your method by adding optional arguments. Take this as an example

What are implied generic type parameters

So, I ran across an answer by Servy ( https://stackoverflow.com/a/15098242/496680 ) and some of his code does this:
public static int BinarySearch<TSource, TKey>(...)
for an extension method, but he calls it like this:
arr.BinarySearch(...)
I asked around and somebody metioned that its an implied generic type parameter.
I googled them but found no information on them.
I understand how generics work but I'm failing to understand how/when to use these.
Why does servy use them in his extention method?
Is there a more official name for these that I can search for?
Well, you left out the most important part that makes it all work. The type parameters can be inferred by the actual object parameters passed in.
For instance:
static class Extensions {
internal static IEnumerable<U> Test<T, U>(
this IEnumerable<T> items,
Func<T, U> converter) {
foreach (T item in items) {
yield return converter(item);
}
}
}
This extension method works on any IEnumerable class and will convert each item in the enumeration to another type based on the converter you provided. This is standard generics.
Now, there are many ways to call this method:
IEnumerable<int> values = Enumerable.Range<int>(1, 10);
Func<int, string> converter = i => i.ToString("0.00");
// Variation 1, explicit calling
IEnumerable<string> results1 = Extensions.Test<int, string>(values, converter);
// Variation 2, explicit calling with type inference
IEnumerable<string> results2 = Extensions.Test(values, converter);
// Variation 3, extension method calling, still providing explicit types
IEnumerable<string> results3 = values.Test<int, string>(converter);
// Variation 4, extension method with type inference
IEnumerable<string> results4 = values.Test(converter);
All four variations call the same method and return the same result. Type inference works by looking at the parameters passed and automatically inferring their types based on what's being provided. In our examples above, it's able to determine that type T is of type int because we passed in an IEnumerable<int> into the parameter for IEnumerable<T>. It is also able to infer that type U is of type string because we passed in a Func matching the initial type of T with int and returning a string. So the Func<T, U> is filled in with our converter function of Func<int, string>.
From the inference above, it's a standard generic method at that point. Type inference and extension methods are nothing more than convenience/syntactic sugar. In fact, if you decompile the output you can see that extension methods are replaced with static calls and are usually defined with the type parameters explicitly filled out. (This varies based on your decompiler and the set options).
He uses a generic method in this case because it allows his method to work with any type contained within a Collection<T>. The generic method makes this very flexible, and usable for any type. He uses the type inferrence when calling the method because it simplifies the code at the call site.
The automatic handling is called Type Inferrence, and is covered, in detail, in the C# Language Specification, section 7.5.2: Type Inferrence. If you want to understand it in detail, I would recommend downloading the C# language specification.
The term I usually hear is 'type inference'.

an I prevent a specific type using generic restrictions

I have an overload method - the first implementation always returns a single object, the second implementation always returns an enumeration.
I'd like to make the methods generic and overloaded, and restrict the compiler from attempting to bind to the non-enumeration method when the generic type is enumerable...
class Cache
{
T GetOrAdd<T> (string cachekey, Func<T> fnGetItem)
where T : {is not IEnumerable}
{
}
T[] GetOrAdd<T> (string cachekey, Func<IEnumerable<T>> fnGetItem)
{
}
}
To be used with...
{
// The compile should choose the 1st overload
var customer = Cache.GetOrAdd("FirstCustomer", () => context.Customers.First());
// The compile should choose the 2nd overload
var customers = Cache.GetOrAdd("AllCustomers", () => context.Customers.ToArray());
}
Is this just plain bad code-smell that I'm infringing on here, or is it possible to disambiguate the above methods so that the compiler will always get the calling code right?
Up votes for anyone who can produce any answer other than "rename one of the methods".
Rename one of the methods. You'll notice that List<T> has an Add and and AddRange method; follow that pattern. Doing something to an item and doing something to a sequence of items are logically different tasks, so make the methods have different names.
This is a difficult use case to support because of how the C# compiler performs overload resolution and how it decides which method to bind to.
The first issue is that constraints are not part of the signature of a method and won't be considered for overload resolution.
The second problem you've got to overcome is that the compiler chooses the best match from the available signatures - which, when dealing with generics, generally means that SomeMethod<T>(T) will be considered a better match than SomeMethod<T>( IEnumerable<T> ) ... particularly when you've got parameters like T[] or List<T>.
But more fundamentally, you have to consider whether operating on a single value vs. a collection of values is really the same operation. If they are logically different, then you probably want to use different names just for clarity. Perhaps there are some use cases where you could argue that the semantic differences between single objects and collections of objects are not meaningful ... but in that case, why implement two different methods at all? It's unclear that method overloading is the best way to express the differences. Let's look at an example that lends to the confusion:
Cache.GetOrAdd("abc", () => context.Customers.Frobble() );
First, note that in the example above we are choosing to ignore the return parameter. Second, notice that we call some method Frobble() on the Customers collection. Now can you tell me which overload of GetOrAdd() will be called? Clearly without knowing the type that Frobble() returns it's not possible. Personally I believe that code whose semantics can't be readily inferred from the syntax should be avoided when possible. If we choose better names, this issue is alleviated:
Cache.Add( "abc", () => context.Customers.Frobble() );
Cache.AddRange( "xyz", () => context.Customers.Frobble() );
Ultimately, there are only three options to disambiguate the methods in your example:
Change the name of one of the methods.
Cast to IEnumerable<T> wherever you call the second overload.
Change the signature of one of the methods in a way that the compiler can differentiate.
Option 1 is self-evident, so I'll say no more about it.
Options 2 is also easy to understand:
var customers = Cache.GetOrAdd("All",
() => (IEnumerable<Customer>)context.Customers.ToArray());
Option 3 is more complicated. Let's look at ways we can be achieve it.
On approach is by changing the signature of the Func<> delegate, for instance:
T GetOrAdd<T> (string cachekey, Func<object,T> fnGetItem)
T[] GetOrAdd<T> (string cachekey, Func<IEnumerable<T>> fnGetItem)
// now we can do:
var customer = Cache.GetOrAdd("First", _ => context.Customers.First());
var customers = Cache.GetOrAdd("All", () => context.Customers.ToArray());
Personally, I find this option terribly ugly, unintuitive, and confusing. Introducing an unused parameter is terrible ... but, sadly it will work.
An alternative way of changing the signature (which is somewhat less terrible) is to make the return value an out parameter:
void GetOrAdd<T> (string cachekey, Func<object,T> fnGetItem, out T);
void GetOrAdd<T> (string cachekey, Func<IEnumerable<T>> fnGetItem, out T[])
// now we can write:
Customer customer;
Cache.GetOrAdd("First", _ => context.Customers.First(), out customer);
Customer[] customers;
var customers = Cache.GetOrAdd("All",
() => context.Customers.ToArray(), out customers);
But is this really better? It prevents us from using these methods as parameters of other method calls. It also makes the code less clear and less understandable, IMO.
A final alternative I'll present is to add another generic parameter to the methods which identifies the type of the return value:
T GetOrAdd<T> (string cachekey, Func<T> fnGetItem);
R[] GetOrAdd<T,R> (string cachekey, Func<IEnumerable<T>> fnGetItem);
// now we can do:
var customer = Cache.GetOrAdd("First", _ => context.Customers.First());
var customers = Cache.GetOrAdd<Customer,Customer>("All", () => context.Customers.ToArray());
So can use hints to help the compiler to choose an overload for us ... sure. But look at all of the extra work we have to do as the developer to get there (not to mention the introduced ugliness and opportunity for mistakes). Is it really worth the effort? Particularly when an easy and reliable technique (naming the methods differently) already exists to help us?
Use only one method and have it detect the IEnumerable<T> case dynamically rather than attempting the impossible via generic constraints. It would be "code smell" to have to deal with two different cache methods depending on if the object to store/retrieve is something enumerable or not. Also, just because it implements IEnumerable<T> does not mean it is necessarily a collection.
constraints don't support exclusion, which may seem frustrating at first, but is consistent and makes sense (consider, for example, that interfaces don't dictate what implementations can't do).
That being said, you could play around with the constraints of your IEnumerable overload...maybe change your method to have two generic typings <X, T> with a constraint like "where X : IEnumerable<T>" ?
ETA the following code sample:
void T[] GetOrAdd<X,T> (string cachekey, Func<X> fnGetItem)
where X : IEnumerable<T>
{
}

Categories