[英]C# Language: How to get type of bound but open Generic class?
假设我有这样一个通用的 class
public class XClass<T, U>
{
public void MethodA<V>(){}
}
我怎么能得到类型
XClass<int,>
没有硬编码,不限于 MakeGenericType 方法如下。
------ 下面详细阐述使用 MakeGenericType ------
我可以得到未绑定的类型并打开 class "XClass<,>" 及其打开方法:
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));
另外,我可以得到全封闭 class 的类型
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));
现在,我怎样才能得到绑定的类型但打开 class
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 cannot be null”。
我应该怎么办?
你提议做的事情是不可能的,也不会真正帮助你。
该文件指出(强调我的),
使用 MakeGenericType 构造的类型可以是开放的,即它们的某些类型 arguments可以是封闭泛型方法或类型的类型参数。
这意味着您不能创建代表XClass<int,>
的Type
object 。 你可以做的是:
class Outer<TOuter>
{
class XClass<T, U> {}
}
在这种情况下,您可以创建一个表示Outer<TOuter>.XClass<int, TOuter>
的Type
object 。 但是需要有一个封闭的通用 class。
该文档还指出(参考与上述类似的示例):
Base 等构造类型在发出代码时很有用,但您不能在此类型上调用 MakeGenericType 方法,因为它不是泛型类型定义。 要创建可实例化的封闭构造类型,首先调用 GetGenericTypeDefinition 方法以获取表示泛型类型定义的 Type object,然后使用所需类型 arguments 调用 MakeGenericType。
这意味着如果你有
Type myType = ... // represents Outer<TOuter>.XClass<int, TOuter>
然后要获得XClass<int, string>
的Type
,您首先需要调用myType.GetGenericTypeDefinition()
(从而丢失int
信息),然后调用MakeGenericType
将其放回(连同string
类型参数)。 所以这就像后退一步,前进两步。
您可能需要考虑将XClass
的类型参数类型存储在单独的数据结构(例如Type[]
)中,只要您不知道所有类型参数,然后在您拥有之后在一个 go 中创建封闭的泛型类型收集了所有这些。
为方便起见,您也可以将 package 这一切变成一个小帮手 class:
class GenericTypeDescription
{
private readonly Type openGenericType;
private readonly Type[] typeParameters;
public GenericTypeDescription(Type openGenericType)
{
// add checks for openGenericType actually being what it says here
this.openGenericType = openGenericType;
this.typeParameters = new Type[openGenericType.GetGenericArguments().Length];
}
public void SetTypeParameter(int index, Type type) {
// add error handling to taste
this.typeParameters[index] = type;
}
public Type ConstructGenericType() {
// add error handling to taste
return this.openGenericType.MakeGenericType(this.typeParameters);
}
}
不,这是不可能的。
请参阅我的类似问题: Does.Net support curried generics?
当您使用自己的通用 arguments 提供 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);
这将使用XClass<int,U>
Type
填充openConstructedType
。
请注意,该类型将具有ContainsGenericParameters
,因此它不可构造,并且无法填充打开的参数。
如果不从 class 继承,我认为这是不可能的。
您似乎正在尝试基本上通过反射来做到这一点:
typeof(XClass<int,>)
这将是半封闭的......并且只有 inheritance AFAIK 才有可能:
class XClassInt<U>: XClass<int, U> {}
第二个代码允许您获取typeof(XClassInt<>).BaseType
这是您想要的。 但是,在这种情况下, XClass<,>
的第二个类型参数不是null
而实际上是U
(来自XClassInt<>
的类型参数)。
另请参阅此 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
的泛型类型参数封闭的。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.