overloading with generics. Is it expected behaviour? [duplicate] - c#

This question already has an answer here:
Closed 10 years ago.
Possible Duplicate:
A problem with generic method overloading
Here is a simple code:
static class Example
{
static int DoIt(object o) { return 0; }
class A { }
static int DoIt(A a) { return 1; }
static int CallDoIt<X>(X x) { return DoIt(x); }
static void Main()
{
var a = new A();
System.Console.WriteLine(DoIt(a)); // returns 1 (as desired)
System.Console.WriteLine(CallDoIt(a)); // returns 0
}
}
The result looks very strange: the function DoIt() called directly returns different value from the case when it is called from another function. Is it expected behaviour in C#? If yes, how to achieve the desired behaviour (preferably without reflection)?

This is the expected behaviour, the knowledge of what type X is does not extend into the CallDoIt function. The overload of DoIt called from CallDoIt is determined statically based on the type of the argument x. Since X can be anything, the best (and only) candidate is DoIt(object).
You can get around this behaviour by delaying the dispatch to DoIt until runtime using dynamic:
static int CallDoIt<X>(X x) { return DoIt((dynamic)x); }
The other alternative is to provide a more specific version of CallDoIt:
static int CallDoIt(A a) { return DoIt(a); }

Method call DoIt(x) inside method CallDoIt<X>(X x) must work for any X type, so C# compiler chose to use DoIt(object o) overload.
If you restrict X type to derive from type A like this:
static int CallDoIt<X>(X x) where X : A { return DoIt(x); }
Then C# compiler will know it can chose DoIt(A a) overload since X type will always derive from type A. This also answers your second question of how to achieve the desired behaviour.

Yes, that is the expected behaviour. A generic method is compiled once for all possible arguments. During that single compilation, DoIt(x) cannot be resolved to DoIt(A), so it is DoIt(object), and that is what it will always be.
You can dynamically check the object type, or better yet, have .NET Framework do so for you:
static int CallDoIt(object x) { return DoIt((dynamic)x); }
Note that there is no benefit here to making CallDoIt generic: it would do exactly the same as this version. That means that CallDoIt((object)a) calls DoIt(A), not DoIt(object).

Add another overload for CallDoIt:
static int CallDoIt(A x) { return DoIt(x); }
This will make things work.

The overload resolution occurs at compile time (if no dynamic resolution needed) and most specific type for X(type parameter) is object.

The decision of choose calling method will be resolved at compile time. The C# compiler does not know what is the type X and choosed the method with DoIt(object o).

Related

Why is this method invocation ambiguous?

Why does the first call to Foo below compile but the second one results in an ambiguous invocation compiler error?
(using c# 7.2)
private static void AmbiguousAsyncOverload() {
Foo(() => Bar()); // This is OK
//Foo(Bar); // Error, ambiguous overload
}
private static void Foo(Func<int> func) {
func();
}
private static void Foo(Func<string> func) {
func();
}
private static int Bar() {
return 4;
}
If I remove the first (Func<int>) implementation of Foo, and hence the possibility of ambiguity, then the compiler (correctly) reports that Bar doesn't have the correct signature to be passed into Foo, which implies it has enough information to resolve the ambiguity.
I would understand if the compiler didn't look at return values during overload resolution and therefore both calls failed, but my question is why does one call compile ok while the other doesn't.
This was an issue for all versions of C# up until it was fixed in v7.3. Return types were not taken into account during overload resolution. From the release notes (or the language proposal) for C# 7.3:
For a method group conversion, candidate methods whose return type doesn't match up with the delegate's return type are removed from the set.

Generics methods overload resolution [duplicate]

I am trying to create a generic method in C#, which will call different methods based on the argument datatype in its body and process their result afterwards. I am trying to achieve this by creating a generic wrapper method and then provide several overloads of the processing method - including a generic one that'll be used if no specific overload is available.
When I call the processing method directly, appropriate version is correctly selected. However when I call it from the wrapper method it always selects the generic one, even if there's a matching overload for the specific datatype I passed to it.
Is there any way to adjust the code to make it behave the way I need to? Or do I have to use a different approach.
I need the code to be compatible with Mono 2.6.
using System;
class Program
{
static void Func<T>(T val)
{
Console.WriteLine("Generic Func");
}
static void Func(int val)
{
Console.WriteLine("Int Func");
}
static void Func(string val)
{
Console.WriteLine("String Func");
}
static void FuncWrap<T>(T val)
{
Console.Write("Wrap: ");
Func(val);
}
static void Main(string[] args)
{
Func(2);
Func("Potato");
Func(2.0);
FuncWrap(2);
FuncWrap("Potato");
FuncWrap(2.0);
Console.Read();
}
}
Is there any way correct this behavior?
It's already the correct behaviour according to the C# language specification. The overload of Func called within FuncWrap is normally determined at compile time, so it can't pick a different Func overload based on the execution-time type.
One way of changing the behaviour, however, is to use dynamic typing:
static void FuncWrap<T>(T val)
{
Console.Write("Wrap: ");
dynamic x = val;
Func(x);
}
That will now perform overload resolution at execution time based on the actual type of the value of x. This incurs a performance cost, but should do what you want it to.
Alternatively, you could hard-code knowledge of the overloads:
static void FuncWrap<T>(T val)
{
Console.Write("Wrap: ");
if (typeof(T) == typeof(string))
{
Func((string)(object)val);
}
else if (typeof(T) == typeof(int))
{
Func((int)(object)val);
}
else
{
Func(val);
}
}
That's clearly pretty horrible though.

Generic method handles IEnumerable differently than generic type

Please check the following codes segments:
public interface ICountable { }
public class Counter<T>
where T : ICountable
{
public int Count(IEnumerable<T> items)
{
return 0;
}
public int Count(T Item)
{
return 0;
}
}
public class Counter
{
public int Count<T>(IEnumerable<T> items)
where T : ICountable
{
return 0;
}
public int Count<T>(T Item)
where T : ICountable
{
return 0;
}
}
The two versions of Counter differ only in the specification of the generic parameter. One of them defines as a generic type parameter, the other as a generic argument. Both restrict the method arguments to implement the ICountable interface. I will call them specific and non specific respectively.
Now, I am defining a class that implements the ICountable interface, and a collection of instances:
public class CItem : ICountable { }
var countables = new List<CItem>();
Then, I would like to use both Counter classes on the collection.
var specific = new Counter<CItem>();
var nonspecific = new Counter();
specific.Count(countables);
nonspecific.Count(countables);
The specific counter recognizes that the countables collection should fall into the signature int Count(IEnumerable), but the non specific version does not. I get the error:
The type 'System.Collections.Generic.List<CItem>' cannot be used as
type parameter 'T' in the generic type or method
'Counter.Count<T>(T)'. There is no implicit reference conversion from
List<CItem>' to ICountable.
It seems that the non specific version uses the wrong signature for the collection.
Why do they behave differently?
How can the non specific version be specified in order to behave the same as the other?
Note: I know this example is not realistic. However, I faced this problem in a quite complicate scenario with extension methods. I use these classes for the sake of simplicity
Thanks in advance
The problem with nonspecific class is that compiler doesn't know the type T in compile time that's why it cannot select correct overload for method Count<T>(). However if you set generic type constraints compiler now knows what type to expect...
If you'll comment out your method with signature public int Count<T>(T Item) it'll compile because it'll use method with correct signature (which is public int Count<T>(IEnumerable<T> items))
It'll also compile and run if you help compiler to infer type by casting your List to IEnumerable<CItem> explicitly :
nonspecific.Count(countables as IEnumerable<CItem>);
Have a look at simplified scenario :
static string A<T>(IEnumerable<T> collection)
{
return "method for ienumerable";
}
static string A<T>(T item)
{
return "method for single element";
}
static void Main(string[] args)
{
List<int> numbers = new List<int>() { 5, 3, 7 };
Console.WriteLine(A(numbers));
}
Output : "method for single element"
If I remember correctly (will try to find a reference in the specification), the T method is chosen because it's an exact match for the type.
The type inference, correctly identifies that both generic methods are applicable, as Count<CItem>(IEnumerable<CItem> items) and Count<List<CItem>>(List<CItem> items). However, the first one loses in the overload resolution, as the second one is more specific. The constraints only come in play after that, so you get a compile time error.
If you declare your countables using
IEnumerable<CItem> countables = new List<CItem>();
then the choice becomes Count<CItem>(IEnumerable<CItem> items) and Count<IEnumerable<CItem>>(IEnumerable<CItem> items) and the first one wins the overload resolution.
In my opinion, the reason why the compiler thinks that you are calling Counter.Count(T) instead of Counter.Count< T >(IEnumerable< T >) is because the later one requires a conversion from List to IEnumerable. And that has a priority less than using the former signature Counter.Count(T), which result in an error.
I think it's better that you change the method name of the one taking an IEnumerble as the argument into something like CountAll. The some thing .NET framework does for List.Remove and List.RemoveAll. It's a good practice to make your code more specific rather than letting the compiler to do all the decisions.

Method overloading in generic class

I am working with a code that contains following overloaded method in generic class:
public class A<T>
{
public void Process(T item) { /*impl*/ }
public void Process(string item) { /*impl*/ }
}
When parametrizing the class for string do I lose the possibility to call the version with generic parameter?
var a = new A<string>();
a.Process(""); //Always calls the non-generic Process(string)
Specific types take precedence over generic types.
For example, this is what I tested with in LINQPad.
void Main()
{
new A<string>().Process("Hello");
}
public class A<T>
{
public void Process(T item) { Console.WriteLine("T"); }
public void Process(string item) { Console.WriteLine("string"); }
}
// Output: string
If you have a problem with hiding the generic method, then you need to rethink something. By overloading a generic method with specific types, you are effectively saying, "Use the generic overload if you need to, but if you can, use the specific version, because it should know what is best."
There is one way I just discovered, but it's a bit cross-eyed. Because generics and overloading get resolved in build time, you can define a generic method:
public static CallerClass
{
public static CallGenericOverload<T>(GenericClass<T> cls, T val)
{
return cls.ProblemOverload(val);
}
//We can also make an extension method.
//We don't have to of course, it's just more comfortable this way.
public static CallGenericOverloadExtension<T>(this GenericClass<T> cls, T val)
{
return cls.ProblemOverload(val);
}
}
public GenericClass<T>
{
public string ProblemOverload(T val)
{
return "ProblemOverload(T val)";
}
public string ProblemOverload(string val)
{
return "ProblemOverload(string val)";
}
}
Now, if we do the following:
var genClass = new GenericClass<string>();
Console.WriteLine(genClass.ProblemOverload("")); //output: ProblemOverload(string val)
Console.WriteLine(CallerClass.CallGenericOverload(genClass, "")); //output: ProblemOverload(T val)
Console.WriteLine(genClass.CallGenericOverloadExtension("")); //output: ProblemOverload(T val)
You can use a similar trick if you define a generic class instead of a generic method. The important thing is that the parameter you transfer to ProblemOverload needs to be of type T rather than type string in the invocation. After all, the method CallGenericOverload knows it's getting a T at build time, so it's going to bind to the overload that accepts the parameter. It doesn't matter that it's actually going to get a string at runtime.
Yes. This is documented in the C# spec, section 7.5.3, overload resolution.
From 7.5.3.6:
"While signatures as declared must be unique, it is possible that substitution of type arguments results in identical signatures. In
such cases, the tie-breaking rules of overload resolution above will
pick the most specific member."
The example given in there states that in the case below, overload resolution for G<int>.F1 will pick non-generic
class G1<U>
{
int F1(U u);
int F1(int i);
}
The tie-breaking rule that applies here is outlined in 7.5.3.2, "Better function member":
In case the parameter type sequences {P1, P2, …, PN} and {Q1, Q2, …,
QN} are equivalent (i.e. each Pi has an identity conversion to the
corresponding Qi), the following tie-breaking rules are applied, in
order, to determine the better function member.
If MP is a non-generic method and MQ is a generic method, then MP is better than MQ.
Having done this before, I'm inclined to say "No," but there's always more knowledgable folks who would argue otherwise.
If memory serves, the runtime compiler chooses the most strongly typed overload to execute.
CLARIFICATION
My answer is badly worded, and I deserve the downvote.
The OP asked, "When parametrizing the class for string do I lose the possibility to call the version with generic parameter?" I wasn't answering that "No, you can't do that," but that "No, you don't lose the ability to call the version with the generic parameter."
I should have been more clear.

Is there a way to write an Extension Method that applies to multiple types?

I'm trying to write an extension method that will add the function HasFactor to the class int in C#. This works wonderfully, like so:
static class ExtendInt
{
public static bool HasFactor(this int source, int factor)
{
return (source % factor == 0);
}
}
class Program
{
static void Main()
{
int i = 50;
int f = 2;
bool b = i.HasFactor(f);
Console.WriteLine("Is {0} a factor of {1}? {2}",f,i,b);
Console.ReadLine();
}
}
This works great because variable i in the Main() method above is declared as an int. However, if i is declared as an Int16 or an Int64, the extension method does not show up unless it is explicitly cast as an int or Int32.
I now would like to apply the same HasFactor method to Int16 and Int64. However, I'd rather not write separate extension methods for each type of int. I could write a single method for Int64 and then explicitly cast everything as an Int64 or long in order for the extension method to appear.
Ideally, I'd prefer to have the same extension method apply to all three types without having to copy and paste a lot of code.
Is this even possible in C#? If not, is there a recommended best-practice for this type of situation?
No, this is not possible in C#. You'll have to create one extension method for each type. The closest is to have an extension method that operates on an interface, but in this case there is no INumeric interface or anything similar that is implemented by the various numeric types.

Categories

Resources