C#语言:如何获取绑定但开放的Generic类的类型?

时间:2011-07-15 08:56:56

标签: c# generics

假设我有这样一个通用类

public class XClass<T, U>
{
    public void MethodA<V>(){}
}

我怎样才能得到

的类型
XClass<int,>

不是硬编码,不限于MakeGenericType方法,如下所示。

------使用MakeGenericType ------

进行详细阐述

我可以获得未绑定和开放类的类型“XClass&lt;,&gt;”和它的开放方法:

var type = typeof(XClass<,>);
    Console.WriteLine(String.Format("Type ZClass<,>: \t generic? {0} \t open? {1}"
            , type.IsGenericType, type.IsGenericTypeDefinition));
var method = type.GetMethod("MethodA");
    Console.WriteLine(String.Format("Method MethodA<>: \t generic? {0} \t open? {1}"
            , method.IsGenericMethod, method.IsGenericMethodDefinition));

另外,我可以得到全封闭类的类型

XClass <int, char>

及其密切方法:

var type = typeof(XClass<,>); 
var method = type.GetMethod("MethodA"); 
var fullType = method.DeclaringType.MakeGenericType(new[]{typeof(int), typeof(char)});
    Console.WriteLine(String.Format("Type ZClass<int,char>: \t generic? {0} \t open? {1}"
            , fullType.IsGenericType, fullType.IsGenericTypeDefinition));
var fullTypeOpenMethod = fullType.GetMethod("MethodA");
var fullMethod = fullTypeOpenMethod.MakeGenericMethod(typeof(string));
    Console.WriteLine(String.Format("Method MethodA<String>:\t generic? {0} \t open? {1}"
            , fullMethod.IsGenericMethod, fullMethod.IsGenericMethodDefinition));

现在,我如何获得绑定但开放类的类型

XClass<int, >

及其方法?

var type = typeof(XClass<,>); 
var method = type.GetMethod("MethodA");
Type [] types = new Type[2];
types[0] = typeof(int);
types[1] = null; // what shall i put here?
var halffullType = method.DeclaringType.MakeGenericType(types);

如果我将types [1]设为null,则ArgumentNullException异常将抛出“Value not not null”。

我该怎么办?

4 个答案:

答案 0 :(得分:3)

你提出的建议是不可能的,也不会对你有所帮助。

不可能,因为......

The documentation陈述(强调我的)

  

使用MakeGenericType构造的类型可以是打开的,也就是说,某些类型   它们的类型参数可以是封闭泛型的类型参数   方法或类型

这意味着您无法创建代表Type的{​​{1}}对象。您可以做的是:

XClass<int,>

在这种情况下,您可以创建一个代表class Outer<TOuter> { class XClass<T, U> {} } 的{​​{1}}对象。但是需要有一个封闭的泛型类。

没用,因为......

文档还指出(参考上面的类似示例):

  

Base等构造类型在发出代码时很有用,   但是你不能在这种类型上调用MakeGenericType方法,因为它   不是泛型类型定义。创建闭合构造类型   可以实例化,首先调用GetGenericTypeDefinition   获取表示泛型类型定义的Type对象的方法   然后使用所需的类型参数调用MakeGenericType。

这意味着如果你有

Type

然后要为Outer<TOuter>.XClass<int, TOuter>获取Type myType = ... // represents Outer<TOuter>.XClass<int, TOuter> ,您首先需要致电Type(从而丢失XClass<int, string>信息),然后致电myType.GetGenericTypeDefinition()它返回(以及int类型参数)。所以这就像退后一步,前进了两步。

替代

您可能需要考虑将MakeGenericType的类型参数类型存储在单独的数据结构中(例如string),只要您不知道所有类型参数,然后创建在收集完所有类型之后,一次性关闭泛型类型。

为方便起见,您还可以将所有这些打包成一个小帮助类:

XClass

答案 1 :(得分:2)

不,这是不可能的。

请参阅我的类似问题:Does .Net support curried generics?

答案 2 :(得分:1)

当您使用自己的通用参数提供MakeGenericType时,

var type = typeof(XClass<,>); 
var method = type.GetMethod("MethodA");
Type[] types = new Type[2];
types[0] = typeof(int);
types[1] = type.GetGenericArguments()[1]; // Use the open parameter type
var openConstructedType = type.MakeGenericType(types);

这将使用openConstructedType Type填充XClass<int,U>

请注意,该类型将具有ContainsGenericParameters,因此它不可构造,并且无法填充打开的参数。

答案 3 :(得分:0)

我认为如果没有继承课程,这是可能的。

你似乎要尝试的是基本上通过反思来做到这一点:

typeof(XClass<int,>)

这将是半封闭的...并且只能通过继承AFAIK来实现:

class XClassInt<U>: XClass<int, U> {}

这第二段代码可让您获得typeof(XClassInt<>).BaseType这就是您想要的。但是,在这种情况下,XClass<,>的第二个类型参数不是null,而是U(来自XClassInt<>的类型参数)。

另见this MSDN页。

修改:这是我的测试平台:

public class C1<A,B> {}

public class C2<B>: C1<int, B> {}

[...]
Type baseType = typeof(C2<>).BaseType;
WL(baseType);
WL(baseType.GetGenericArguments()[0]);
Type arg1 = baseType.GetGenericArguments()[1];
WL(arg1);
WL(arg1.DeclaringType);
WL(arg1.GenericParameterPosition);
WL(arg1.IsGenericParameter);

运行此产生:

C1`2[System.Int32,B]
System.Int32
B
C2`1[B]
0
True

但是,正如我所说,我认为这是可能的,因为基类型是使用开放泛型类型C2的泛型类型参数关闭的。