2013-03-26 54 views
6

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

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进行这样的比较吗?

+0

那么,在每一种情况下,你是从绑定的泛型列表采购的调用链,所以声明类型将永远是未绑定的泛型类型。你想做什么? – JerKimball 2013-03-26 16:49:33

回答

15

你混淆了两种不同类型,它们都命名为T.想想看这样的:

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

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

什么是接口实施Foo<TFOO>?那是IFoo<TFOO>

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

什么类型申报TFOOFoo<TFOO>宣布它。

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

什么类型申报TFOOFoo<TFOO>宣布它。 不是IFoo<TFOO>TFOO来自Foo

有意义吗?

+0

我不遵循从“什么类型*声明* TFOO”到为什么接口类型打印出为'System.Collections.Generic.List'1 [T]'的步骤。在MSDN示例中,* interfaces *的名称是用*具体类型*打印的。我不明白为什么谁声明'TFOO'的问题导致打印出类的名称而不是接口的名称。 http://msdn.microsoft.com/en-us/library/system.type.getinterfaces.aspx – 2013-03-26 16:55:55

+0

@EricJ .:链接中的示例不使用'.DeclaringType'。 – recursive 2013-03-26 16:57:45

+0

@recursive:我知道,但我仍然不明白这一步。我很确定Eric Lippert在他的评论中是正确的。 – 2013-03-26 17:01:21

2

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

我想实现我的编译器泛型类型推断......

这样我假设你正在使用反射来构建编译器。这可能不是一个好主意。反思比现在早得多,但与直接使用令牌相比,仍然是重量级的。并且反射发射不能发射类型的每种可能的拓扑;它在涉及嵌套结构类型的一些场景中会变得混乱。

我会考虑使用CCI来代替。我们对Roslyn使用了CCI的修改版本。下面

的代码返回false。

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

这是正确的。参数类型是IList<TMethodParam>listInterfaceTypeIList<T>其中TList<T>声明的通用参数类型,而不是IList<T>声明的通用参数类型。这些都是不同的类型。

我应该总是使用Type.GetGenericTypeDefinition进行这样的比较吗?

如果您想查看两个泛型类型是否都是相同泛型的结构,那么是的。如果这不是你想要检查的,那么不。

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

这是使用基于标记的方法而不是基于反射型对象的方法的另一个原因。当你有令牌时,区分TypeDefTypeRef要容易得多。