Expression.GetDelegateType和泛型方法

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

我需要使用以下方法创建具有Reflection的委托:

public void Serialize<TElement>(IList<TElement> value)
{
}

这些方法的共同之处在于它们返回Void并且具有一个带有一个泛型参数的参数。参数类型不一定是IList<T>。在代理人的调用之前,我无法解决TElement

使用以下方法引发异常:

static Delegate CreateOpenDelegate(MethodInfo method, object target)
{
    var args = new List<Type>(method.GetParameters()
        .Select(param => param.ParameterType));
    args.Add(method.ReturnType);
    var delegateType = Expression.GetDelegateType(args.ToArray());
    return Delegate.CreateDelegate(delegateType, target, method);
}

是否有一个可行的替代方法在运行时创建委托,就在它执行之前(一旦TElement变得已知并且可以在方法上调用MakeGenericMethod)?

c# generics reflection delegates expression-trees
1个回答
0
投票

我的理解是Delegate类(不要与delegate关键字混淆)只能从可以调用的MethodInfo创建。如果IsGenericMethod为true且ContainsGenericParameters = true,则无法调用MethodInfo。 More Information on this.

话虽如此,如果在需要创建委托时在运行时知道所有类型,则可以从它们构造委托。如果由于某种原因它们不是,您可能需要重新构建代码,以便更密切地创建委托给它的调用。

static Delegate CreateOpenDelegate(MethodInfo method, object instance, params Type[] genericParameters)
{
    var myMethod = method.IsGenericMethod ? method.MakeGenericMethod(genericParameters) : method;
    var args = new List<Type>(myMethod.GetParameters()
        .Select(param => param.ParameterType));
    args.Add(myMethod.ReturnType);
    var delegateType = Expression.GetDelegateType(args.ToArray());
    return myMethod.CreateDelegate(delegateType, instance);
}

下面是使用Serialize的示例,但作为类Program的静态实例(只是因为它很方便,如果您愿意,可以将其作为实例参数)。

static void Main(string[] args)
{
    var method = typeof(Program).GetMethod("Serialize");
    object myCollection = "12345".ToCharArray();
    //Get the element type for the array. In this case it is typeof(char)
    Delegate test = CreateOpenDelegate(method, null, myCollection.GetType().GetElementType());
    test.DynamicInvoke(myCollection);

    myCollection = new List<int> { 1, 2, 3, 4, 5 };
    //Get the generic argument for the collection type. In this case it is typeof(int)
    test = CreateOpenDelegate(method, null, myCollection.GetType().GetGenericArguments()[0]);
    test.DynamicInvoke(myCollection);
}

public static void Serialize<TElement>(IList<TElement> value)
{
}

收集类型可能因您的具体情况而异。我用两种不同的方式获得了类型,但是通过在GetType()上调用GetInterfaces()然后找到IList接口并从该接口获取泛型类型,也可以更好地抽象出来。

您在第一次使用它时可能犯的最大错误是错误地将整个IList类型作为泛型参数传递而不是获取IList泛型参数。至少我知道我仍然经常这样做。

© www.soinside.com 2019 - 2024. All rights reserved.