繁体   English   中英

C# 语言:如何获取绑定但打开的通用 class 类型?

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM