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 anIPet
, the variable passed into the generic method is anIPet
at compile time despite being aDog
at runtime. Thus the compiler usesIPet
for the generic parameter, even though the object at runtime is aDog
. Since you usedtypeof(T)
, you get the exact type given to the generic method by the compiler.This can be seen by changing the type of
_dog
toDog
instead ofIPet
, which will then cause the compiler to infer the correct type.This can also be avoided by explicitly casting the object 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, sincedynamic
types are rather slow.