如何从具有基本类型约束的泛型方法中获取 typeof(T)?

How to get the typeof(T) from a generic method with base type constraint?

我有以下规范来帮助说明问题:

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

上述规范失败并显示以下消息:

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

我需要结果的类型为 Dog。有什么我可以不使用反射来做的吗?

这里的问题是在运行时与编译时使用的类型。

因为您将 _dog 声明为 IPet,传递给泛型方法的变量在编译时是 IPet,尽管在运行时是 Dog。因此,编译器使用 IPet 作为泛型参数,即使运行时的对象是 Dog。由于您使用了 typeof(T),因此您获得了编译器赋予泛型方法的确切类型。

这可以通过将 _dog 的类型更改为 Dog 而不是 IPet 来看出,这将导致编译器推断出正确的类型。

这也可以通过将对象显式转换为 dynamic:

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

这将强制编译器将类型推断推迟到运行时,此时它将确定对象的类型为 Dog。然而,这对于生产代码通常不是一个好主意,因为 dynamic 类型相当慢。

只需将约束 "class" 添加到您的方法中即可:

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