C# – How to Get the typeof(T) from a Generic Method with Base Type Constraint

.netc++generics

I have the following spec to help illustrate the problem:

class when_getting_type_of_generic_argument_using_subtype_instance
{
    static GenericTypeTester _genericTypeTester;
    static IPet _dog;
    static Type _result;

    Establish context =
        () =>
        {
            _genericTypeTester = new GenericTypeTester();

            _dog = new Dog();
        };

    Because of =
        () => _result = _genericTypeTester.Test(_dog);

    It should_return_the_subtype =
        () => _result.ShouldEqual(_dog.GetType());
}

class Dog : IPet
{
}

interface IPet
{
}

class GenericTypeTester
{
    public Type Test<T>(T dog) where T : IPet
    {
        return typeof (T);
    }
}

The spec above fails with the following message:

Expected: System.RuntimeType:[Pepino.ScenarioRunner.Selenium.Specs.Dog]
But was: System.RuntimeType:[Pepino.ScenarioRunner.Selenium.Specs.IPet]

I need the result to be of type Dog. Is there something I can do without using reflection?

Best Answer

The issue here is the type being used at runtime versus compile time.

Because you declared _dog as an IPet, the variable passed into the generic method is an IPet at compile time despite being a Dog at runtime. Thus the compiler uses IPet for the generic parameter, even though the object at runtime is a Dog. Since you used typeof(T), you get the exact type given to the generic method by the compiler.

This can be seen by changing the type of _dog to Dog instead of IPet, which will then cause the compiler to infer the correct type.

This can also be avoided by explicitly casting the object as dynamic:

() => _result = _genericTypeTester.Test(_dog as dynamic);

Which will force the compiler to hold off the type inference until runtime, at which point it will determine that the object is type Dog. This is generally not a good idea for production code, however, since dynamic types are rather slow.

Related Question