通用的奇怪行为

时间:2013-03-26 16:45:22

标签: c#

我遇到了泛型的奇怪行为。下面是我用于测试的代码。

public static class Program
{
    public static void Main()
    {
        Type listClassType = typeof(List<int>).GetGenericTypeDefinition();
        Type listInterfaceType = listClassType.GetInterfaces()[0];

        Console.WriteLine(listClassType.GetGenericArguments()[0].DeclaringType);
        Console.WriteLine(listInterfaceType.GetGenericArguments()[0].DeclaringType);
    }
}

输出:

System.Collections.Generic.List`1[T]
System.Collections.Generic.List`1[T]

我发现第二个Console.WriteLine调用显示的是一个类而不是一个接口,这很奇怪,因为我使用泛型类型定义。这是正确的行为吗?

我正在尝试在编译器中实现泛型类型推断。假设我有以下代码。

public static class GenericClass
{
    public static void GenericMethod<TMethodParam>(IList<TMethodParam> list) { }
}

我想按如下方式调用此方法:

GenericClass.GenericMethod(new List<int>());

为了检查推理的可能性,我必须比较方法签名中的类型和传递的参数类型。但是下面的代码返回false。

typeof(GenericClass).GetMethods()[0].GetParameters()[0].ParameterType == listInterfaceType;

我是否应该始终使用Type.GetGenericTypeDefinition进行此类比较?

2 个答案:

答案 0 :(得分:15)

你混淆了两种名为T的不同类型。想想这样:

interface IFoo<TIFOO> { }
class Foo<TFOO> : IFoo<TFOO> {}

好的,Foo<int>泛型类型定义是什么?那是Foo<TFOO>

Foo<TFOO> 实施的界面是什么?那是IFoo<TFOO>

Foo<TFOO>类型参数是什么?显然是TFOO

什么类型的声明 TFOOFoo<TFOO>宣布了它。

IFoo<TFOO>类型参数是什么?显然TFOO TIFOO

什么类型的声明 TFOOFoo<TFOO>宣布了这一点。 IFoo<TFOO>TFOO来自Foo

有意义吗?

答案 1 :(得分:2)

添加第二个答案,因为您添加了第二个问题:

  

我试图在我的编译器中实现泛型类推理......

因此我假设您正在使用反射来构建编译器。这可能不是一个好主意。现在反思比早期反映更高效,但与直接使用令牌相比,它仍然是重量级的。并且反射发射不能发出每种可能的类型拓扑;在涉及嵌套结构类型的某些场景中,它会搞砸。

我会考虑使用CCI。我们在Roslyn中使用了CCI的修改版本。

  

以下代码返回false。

typeof(GenericClass).GetMethods()[0].GetParameters()[0].ParameterType == listInterfaceType

那是对的。参数类型为IList<TMethodParam>listInterfaceTypeIList<T>,其中TList<T>声明的泛型参数类型,而不是{IList<T>声明的泛型参数类型。 1}}。这些都是不同的类型。

  

我是否应该始终使用Type.GetGenericTypeDefinition进行此类比较?

如果要查看两个泛型类型是否都是相同泛型类型的构造,是的。如果那不是您要检查的内容,那么不。

这种类型系统很复杂,所以要非常小心。

这是使用基于令牌的方法而不是基于反射类型对象的方法的另一个原因。当您拥有令牌时,可以更轻松地区分TypeDefTypeRef