我有以下规范来帮助说明问题:
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);
}
}
上述规范失败,并显示以下消息:
预期:System.RuntimeType:[Pepino.ScenarioRunner.Selenium.Specs.Dog] 但是:System.RuntimeType:[Pepino.ScenarioRunner.Selenium.Specs.IPet]
我需要结果为Dog
类型。有没有我可以做的事情而不使用反射?
答案 0 :(得分:2)
这里的问题是运行时使用的类型与编译时间的对比。
因为您将_dog
声明为IPet
,所以在编译时传递给泛型方法的变量是IPet
,尽管在运行时是Dog
。因此,编译器使用IPet
作为泛型参数,即使运行时的对象是Dog
。由于您使用了typeof(T)
,因此您可以获得编译器为泛型方法指定的确切类型。
可以通过将_dog
的类型更改为Dog
而不是IPet
来查看,这将导致编译器推断出正确的类型。
通过将对象明确地转换为dynamic
:
() => _result = _genericTypeTester.Test(_dog as dynamic);
这会强制编译器在运行时延迟类型推断,此时它将确定对象是类型Dog
。但是,这通常不是生产代码的好主意,因为dynamic
类型相当慢。
答案 1 :(得分:0)
只需将约束“class”添加到您的方法中:
class GenericTypeTester
{
public Type Test<T>(T dog) where T : IPet, class
{
return typeof (T);
}
}