Overloading with generics. Is the behavior expected?
Possible duplicate:
Problem with overloading generic methods
Here's 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 called DoIt () function calls the direct value from the case when it is called from another function. Is the behavior expected in C #? If so, how to achieve the desired behavior (preferably without reflection)?
This is the expected behavior, knowing that the type X
does not extend to the function CallDoIt
. The overload DoIt
called from CallDoIt
is statically determined based on the type of the argument X
. Since it X
can be anything, the best (and only) candidate is DoIt(object)
.
You can work around this behavior by deferring the dispatch DoIt
until it works dynamically:
static int CallDoIt<X>(X x) { return DoIt((dynamic)x); }
Another alternative is to provide a more specific version CallDoIt
:
static int CallDoIt(A a) { return DoIt(a); }
Calling a method DoIt(x)
inside a method CallDoIt<X>(X x)
should work for any type X
, so the C # compiler decided to use an overload DoIt(object o)
. If you constrain type X
to type A
like this:
static int CallDoIt<X>(X x) where X : A { return DoIt(x); }
Then the C # compiler will know that it can choose to overload DoIt(A a)
, since the type X
will always be inferred from the type A
. This also answers your second question on how to achieve the desired behavior.
Yes, this is expected behavior. The generic method is compiled once for all possible arguments. During this single compilation, DoIt(x)
it cannot be resolved before DoIt(A)
, so it is DoIt(object)
, and it will be.
You can check the object type dynamically, or better yet, have the .NET Framework for you:
static int CallDoIt(object x) { return DoIt((dynamic)x); }
Note that there is no benefit to creating a CallDoIt
generic here: it will do the same as this version. This means what CallDoIt((object)a)
is calling DoIt(A)
, not DoIt(object)
.
Add another overload for CallDoIt:
static int CallDoIt(A x) { return DoIt(x); }
It will work.
Overload resolution occurs at compile time (if no dynamic resolution is required) and the most specific type for X
(type parameter) is object
.
The decision to choose a calling method will be resolved at compile time. The C # compiler doesn't know what type X is and chose a method with DoIt (object o).