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)?

+3


source to share


6 answers


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); }

      

+2


source


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.

+1


source


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)

.

0


source


Add another overload for CallDoIt:

static int CallDoIt(A x) { return DoIt(x); }

      

It will work.

0


source


Overload resolution occurs at compile time (if no dynamic resolution is required) and the most specific type for X

(type parameter) is object

.

0


source


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).

0


source







All Articles