简体   繁体   English

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

[英]C# Language: How to get type of bound but open Generic class?

Let's say I have such a generic class假设我有这样一个通用的 class

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

How could I get the type of我怎么能得到类型

XClass<int,>

not hard-coded, not limiting to MakeGenericType method as below.没有硬编码,不限于 MakeGenericType 方法如下。

------ detailed elaboration below using MakeGenericType ------ ------ 下面详细阐述使用 MakeGenericType ------

I can get the type of the unbound and open class "XClass<,>" and its open method:我可以得到未绑定的类型并打开 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));

Also, I can get the type of full closed class另外,我可以得到全封闭 class 的类型

XClass <int, char>

and its close method:及其关闭方法:

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));

Now, How can I get the type of bound but open class现在,我怎样才能得到绑定的类型但打开 class

XClass<int, >

and its method?及其方法?

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);

If I put types[1] as null, an ArgumentNullException exception will throw "Value cannot be null".如果我将 types[1] 设置为 null,ArgumentNullException 异常将抛出“Value cannot be null”。

What should I do?我应该怎么办?

What you are proposing to do is impossible and also will not really help you.你提议做的事情是不可能的,也不会真正帮助你。

Impossible because...不可能,因为...

The documentation states (emphasis mine) that 该文件指出(强调我的),

Types constructed with MakeGenericType can be open, that is, some of their type arguments can be type parameters of enclosing generic methods or types .使用 MakeGenericType 构造的类型可以是开放的,即它们的某些类型 arguments可以是封闭泛型方法或类型的类型参数

This means that you cannot make a Type object representing XClass<int,> .这意味着您不能创建代表XClass<int,>Type object 。 What you can do is:可以做的是:

class Outer<TOuter>
{
    class XClass<T, U> {}
}

In this situation, you can make a Type object representing Outer<TOuter>.XClass<int, TOuter> .在这种情况下,您可以创建一个表示Outer<TOuter>.XClass<int, TOuter>Type object 。 But there needs to be an enclosing generic class.但是需要有一个封闭的通用 class。

Not useful because...没用,因为...

The documentation also states (referring to a similar example to the above) that:该文档还指出(参考与上述类似的示例):

A constructed type such as Base is useful when emitting code, but you cannot call the MakeGenericType method on this type because it is not a generic type definition. Base 等构造类型在发出代码时很有用,但您不能在此类型上调用 MakeGenericType 方法,因为它不是泛型类型定义。 To create a closed constructed type that can be instantiated, first call the GetGenericTypeDefinition method to get a Type object representing the generic type definition and then call MakeGenericType with the desired type arguments.要创建可实例化的封闭构造类型,首先调用 GetGenericTypeDefinition 方法以获取表示泛型类型定义的 Type object,然后使用所需类型 arguments 调用 MakeGenericType。

Which means that if you have这意味着如果你有

Type myType = ... // represents Outer<TOuter>.XClass<int, TOuter>

Then to get a Type for XClass<int, string> you would first need to call myType.GetGenericTypeDefinition() (thus losing the int information) and then call MakeGenericType to put it back in (along with the string type parameter).然后要获得XClass<int, string>Type ,您首先需要调用myType.GetGenericTypeDefinition() (从而丢失int信息),然后调用MakeGenericType将其放回(连同string类型参数)。 So it's like one step back and two steps forward.所以这就像后退一步,前进两步。

Alternatives备择方案

You might want to consider storing the type parameter types for XClass in a separate data structure (eg a Type[] ) for as long as not all type parameters are known to you, and then create the closed generic type in one go after you have collected all of them.您可能需要考虑将XClass的类型参数类型存储在单独的数据结构(例如Type[] )中,只要您不知道所有类型参数,然后在您拥有之后在一个 go 中创建封闭的泛型类型收集了所有这些。

You can also package all this into a small helper class for convenience:为方便起见,您也可以将 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);
    }
}

No, this isn't possible.不,这是不可能的。

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

This is possible, when you feed MakeGenericType with its own generic arguments.当您使用自己的通用 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);

This will populate openConstructedType with a Type of XClass<int,U> .这将使用XClass<int,U> Type填充openConstructedType

Note that the type will have ContainsGenericParameters , so it won't be constructable, and there's no way to populate the open parameters.请注意,该类型将具有ContainsGenericParameters ,因此它不可构造,并且无法填充打开的参数。

I don't think that this is possible without inheriting from the class.如果不从 class 继承,我认为这是不可能的。

What you seem to be trying is to basically do this via reflection:您似乎正在尝试基本上通过反射来做到这一点:

typeof(XClass<int,>)

This would be half-closed... and only possible by inheritance AFAIK:这将是半封闭的......并且只有 inheritance AFAIK 才有可能:

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

This second code allows you to get typeof(XClassInt<>).BaseType which is kind of what you want.第二个代码允许您获取typeof(XClassInt<>).BaseType这是您想要的。 However, in that case the second type argument for XClass<,> is not null but actually U (the type argument coming from XClassInt<> ).但是,在这种情况下, XClass<,>的第二个类型参数不是null而实际上是U (来自XClassInt<>的类型参数)。

See also this MSDN page.另请参阅此 MSDN页面。

Edit: Here's my testbed for this:编辑:这是我的测试平台:

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);

Running this yields:运行此产生:

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

However, as I said, I believe this is only possible because the base type is closed with the generic type argument of the open generic type C2 .但是,正如我所说,我相信这只是可能的,因为基本类型是用开放泛型类型C2的泛型类型参数封闭的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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