4

Confusing question, I know. Given the following:

    class Test
    {
        public static void GenericFunc<T>(T SomeType)
        {
            System.Console.WriteLine("typeof(T): " + typeof(T).Name);
            System.Console.WriteLine("SomeType.GetType(): " + SomeType.GetType().Name);
        }
    }

    public class BaseType
    {
        public void RunTest() { Test.GenericFunc(this); }
    }

    public class DerivedType : BaseType { }

The following code produces interesting output:

    DerivedType Derived = new DerivedType();
    Derived.RunTest();

    // output:
    // typeof(T): BaseType
    // SomeType.GetType(): DerivedType

However, this behaves as I would expect:

    Test.GenericFunc(new Derived());

    // output:
    // typeof(T): DerivedType
    // SomeType.GetType(): DerivedType

Can anyone help me understand the mechanism here that's causing T to be evaluated as BaseType in the first case?

Thanks in advance!

antlersoft
  • 14,636
  • 4
  • 35
  • 55
Bill Brooks
  • 751
  • 1
  • 10
  • 30

2 Answers2

14

Unless the "dynamic" type is involved, overload resolution and type inference are performed at compile time, not at run time.

When overload resolution sees Test.GenericFunc(this); it must deduce the generic type argument that corresponds to the missing generic type parameter. That is an easy problem; it uses the compile time type of this, and inside a method of BaseType, clearly the compile time type of this is always BaseType.

Therefore overload resolution assumes that you intended to call Test.GenericFunc<BaseType>(this).

If you intend this to be worked out a runtime, you can do that in C# 4. Just say Test.GenericFunc((dynamic)this). That will start the overload resolution engine again at runtime, which will then pretend that you had cast this to its runtime type back at compile time.

Yes, that is every bit as expensive as it sounds. If you want semantic analysis at runtime then we're going to have to run a semantic analyzer at runtime.

Eric Lippert
  • 647,829
  • 179
  • 1,238
  • 2,067
6

Because this:

public class BaseType
{
    public void RunTest() { Test.GenericFunc(this); }
}

Is basically equivalent to:

public class BaseType
{
    public void RunTest() { Test.GenericFunc<BaseType>(this); }
}

Therefore the GenericFunc gets instatiated at compile time with T = BaseType. However the this object you are passing in at runtime is the derived type which you get by SomeType.GetType().

In the second case the compiler infers the type as DerivedType directly from the usage and therefore GenericFunc gets instatiated with T = DerivedType.

ChrisWue
  • 18,612
  • 4
  • 58
  • 83
  • Just goes to show how long I've been away from C++. I know that generics are evaluated at compile time, but for some reason there I got it in my head that it was all happening at run time. Embarrassing. Thanks for the reminder! – Bill Brooks Jul 14 '11 at 20:57