将 `System.Type[]` 中的泛型类型替换为类型

问题描述 投票:0回答:1

假设有一个通用定义

MethodInfo
对象,即一个
MethodInfo
对象,使得
methodInfo.IsGenericMethodDefinition == true
:

MethodInfo methodInfo = somethingCool;

还说他们还有一个通用参数列表:

Type[] genericArguments = somethingElseAlsoCool;

我可以通过以下方式获取方法参数的类型:

Type[] types = (
    from ParameterInfo parameter
    in methodInfo.GetParameters()
    select parameter.ParameterType
    ).ToArray();

现在,我可以用

methodInfo
填写
methodInfo.MakeGenericMethod
的通用参数:

MethodInfo invokableMethodInfo = methodInfo.MakeGenericMethod(genericArguments);

但是,

Type
数组又如何呢?我可以过早地增加这样的类型:

for (int i = 0; i < types.Length; i++)
    types[i] = types[i].MakeGenericType(genericArguments);

但这没有意义。考虑以下方法:

void MyGenericMethod<TOne, TTwo, TThree>(IDictionary<TOne, TThree> Dictionary);

如果我执行前面提到的算法,那么类型将错误映射:

TOne   => TKey   //Fine, but only by coincidence.
TTwo   => TValue //Incorrect. TValue should be TThree, not TTwo.
TThree => ?      //What is this?

我被难住了。 如何在类型数组中定义未定义的泛型?

根据评论中的要求,这是一个测试用例:

using System.Reflection;
using static System.Console;
MethodInfo methodInfo = ((Delegate)MyTest<object, object>).Method.GetGenericMethodDefinition();
Type[] genericArguments = new Type[] { typeof(int), typeof(string) };
MethodInfo invokableMethodInfo = methodInfo.MakeGenericMethod(genericArguments);
WriteLine("----Method Invoke Result:");
invokableMethodInfo.Invoke(null, new object?[] { "hi" });
WriteLine("----End");
Type[] types = (
    from ParameterInfo parameter
    in methodInfo.GetParameters()
    select parameter.ParameterType
    ).ToArray();
WriteLine();
WriteLine("----Undefined Generic Types:");
foreach (Type type in types)
    WriteLine(type);
WriteLine("----End");
types = (
    from ParameterInfo parameter
    in invokableMethodInfo.GetParameters()
    select parameter.ParameterType
    ).ToArray();
WriteLine();
WriteLine("----Defined Generic Types:");
foreach (Type type in types)
    WriteLine(type);
WriteLine("----End");
ReadKey(true);
static void MyTest<TOne, TTwo>(TTwo Value)
{
    WriteLine(typeof(TOne).ToString());
    WriteLine(Value?.ToString());
}

它将输出:

----Method Invoke Result:
System.Int32
hi
----End

----Undefined Generic Types:
TTwo
----End

----Defined Generic Types:
System.String
----End

在我的代码中,我使用

methodInfo
来获取
Defined Generic Types
数组。我想改用
methodInfo
中的类型数组来获得相同的结果。

任何帮助将不胜感激!

c# generics .net-core types reflection
1个回答
0
投票

不确定为什么您不能/不想使用

invokableMethodInfo
来获取“填充”参数类型。如果可以的话,你绝对应该这样做。

否则,您将不得不自己进行“类型替换”。您可以使用

IsGenericMethodParameter
判断参数类型是否为类型参数,并使用
GenericParameterPosition
获取参数类型。
GenericParameterPosition
返回的索引可以直接用于访问您的
genericArguments
数组。

这个想法基本上是,对于方法的每个参数,

  • 如果是类型参数,则替换为
    genericArguments[GenericParameterPosition]
  • 如果是泛型类型,则用此算法递归替换其每个类型参数
  • 如果两者都不是,请勿更改
// perhaps the name of this could be better...
private static Type AssignConcreteTypesToGenericTypeParameter(Type parameter, Type[] arguments) {
    if (parameter.IsGenericMethodParameter) {
        return arguments[parameter.GenericParameterPosition];
    }
    if (parameter.IsGenericType) {
        var typeArguments = parameter.GenericTypeArguments.Select(
            x => AssignConcreteTypesToGenericTypeParameter(x, arguments)
        ).ToArray();
        return parameter.GetGenericTypeDefinition().MakeGenericType(typeArguments);
    }
    return parameter;
}

使用示例:

MethodInfo methodInfo = ((Delegate)MyTest<object, object>).Method.GetGenericMethodDefinition();
Type[] arguments = new[] { typeof(string), typeof(int) };
var actualParameterTypes = methodInfo.GetParameters().Select(
    x => AssignConcreteTypesToGenericTypeParameter(x.ParameterType, arguments)
);
foreach (var t in actualParameterTypes) 
    Console.WriteLine(t);
© www.soinside.com 2019 - 2024. All rights reserved.