Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/339.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 使用参数名动态创建委托_C#_Dynamic_Parameters_Delegates_Expression Trees - Fatal编程技术网

C# 使用参数名动态创建委托

C# 使用参数名动态创建委托,c#,dynamic,parameters,delegates,expression-trees,C#,Dynamic,Parameters,Delegates,Expression Trees,大家好,我正在尝试创建一个函数,该函数动态创建一个委托,该委托的返回值和参数与作为参数接收的MethodInfo相同,这对于相同的参数名非常重要 到目前为止,我所做的是创建一个函数,该函数返回一个lambda,该lambda接收相同的参数类型,并具有与MethodInfo相同的返回值,但它没有参数名称: static void Example() { Person adam = new Person(); MethodInfo method = t

大家好,我正在尝试创建一个函数,该函数动态创建一个委托,该委托的返回值和参数与作为参数接收的MethodInfo相同,这对于相同的参数名非常重要

到目前为止,我所做的是创建一个函数,该函数返回一个lambda,该lambda接收相同的参数类型,并具有与MethodInfo相同的返回值,但它没有参数名称:

    static void Example()
    {
        Person adam = new Person();
        MethodInfo method = typeof(Person).GetMethod("Jump");
        Delegate result = CreateDelegate(adam, method);
        result.DynamicInvoke((uint)4, "Yeahaa");
    }

    private static Delegate CreateDelegate(object instance, MethodInfo method)
    {
        var parametersInfo = method.GetParameters();
        Expression[] expArgs = new Expression[parametersInfo.Length];
        List<ParameterExpression> lstParamExpressions = new List<ParameterExpression>();
        for (int i = 0; i < expArgs.Length; i++)
        {
            expArgs[i] = Expression.Parameter(parametersInfo[i].ParameterType, parametersInfo[i].Name);
            lstParamExpressions.Add((ParameterExpression)expArgs[i]);
        }

        MethodCallExpression callExpression = Expression.Call(Expression.Constant(instance), method, expArgs);
        LambdaExpression lambdaExpression = Expression.Lambda(callExpression, lstParamExpressions);

        return lambdaExpression.Compile();
    }

    private class Person
    {
        public void Jump(uint height, string cheer)
        {
            Console.WriteLine("Person jumped " + height + " "+ cheer);
        }
    }
static void示例()
{
人物亚当=新人();
MethodInfo method=typeof(Person).GetMethod(“跳转”);
委托结果=CreateDelegate(adam,方法);
结果:DynamicInvoke((uint)4,“Yeahaa”);
}
私有静态委托CreateDelegate(对象实例,MethodInfo方法)
{
var parameters sinfo=method.GetParameters();
表达式[]expArgs=新表达式[parametersInfo.Length];
List lstParamExpressions=新列表();
对于(int i=0;i
有人对我如何做到这一点有什么建议吗? 为了说明这一点,我之所以关心参数名,是为了能够用参数名激活委托,这样我就可以这样调用它(cheel=“YAY!”,height=3) (我的应用程序是与Python集成的,这就是我在没有DynamicVoke的情况下能够做到的,这也是参数名如此重要的原因。)
还有为什么我写了“=”而不是“:”)

来动态创建委托,您可以使用Reflection.Emit。由于委托是.Net中的特殊类型,创建它们的代码并不十分明显。以下是基于
Expression.Lambda()使用的方法的反射代码
。在没有可用的
操作
Func
委托的情况下(超过17个参数,或带有
ref
out
的参数),它用于创建自定义委托类型

但实际上,您根本不需要处理
Expression
s。是否足够:

private static Delegate CreateDelegate(object instance, MethodInfo method)
{
    return Delegate.CreateDelegate(
        s_delegateTypeFactory.CreateDelegateType(method), instance, method);
}

开源框架ImpromptuInterface(通过nuget的v5.6.7)有一个DLR应用程序实现,我认为在这种情况下只要您不需要文本委托,它就可以工作

下面是创建和调用它的c#版本:

dynamic jump =Impromptu.Curry(adam).Jump();
jump(cheer:"yay", height:(uint)3);

因此,
jump
不是字面委托,您无法反映它,但您可以直接调用它,就像它是委托,它是DLR对象一样,因此我猜想它在python中也会工作相同。

我刚刚偶然发现了一种解决此问题的好方法,对于静态方法的委托,它看起来是这样的:

private static Delegate CreateDelegate(MethodInfo method) {
    var paramTypes = method.GetParameters().Select(p => p.ParameterType);

    Type delegateType = Expression.GetDelegateType(paramTypes.Append(method.ReturnType).ToArray());

    return Delegate.CreateDelegate(delegateType, method, true);
}
它使用以下扩展方法:

public static IEnumerable<TSource> Append<TSource>(this IEnumerable<TSource> collection, TSource element) {
    if (collection == null) throw new ArgumentNullException("collection");

    foreach (TSource element1 in collection) yield return element1;
    yield return element;
}
公共静态IEnumerable追加(此IEnumerable集合,TSource元素){
如果(collection==null)抛出新的ArgumentNullException(“collection”);
foreach(集合中的TSource元素1)收益返回元素1;
收益-收益要素;
}

谢谢,我今天早些时候试过,效果很好!!我理解你的大部分代码,但我真的不明白你对名称和名称库做了什么,为什么它等于类型库的名称+类型的名称,数字=2是什么?无论如何,非常感谢你,我一直在努力让它工作days@UchihaMadara,我是j我们需要一种方法来确保类型名称是唯一的,因为在同一程序集中不能有两个名称相同的类型。数字2在那里,因此名称类似于
PersonJump
PersonJump2
PersonJump3
,等等。
private static Delegate CreateDelegate(MethodInfo method) {
    var paramTypes = method.GetParameters().Select(p => p.ParameterType);

    Type delegateType = Expression.GetDelegateType(paramTypes.Append(method.ReturnType).ToArray());

    return Delegate.CreateDelegate(delegateType, method, true);
}
public static IEnumerable<TSource> Append<TSource>(this IEnumerable<TSource> collection, TSource element) {
    if (collection == null) throw new ArgumentNullException("collection");

    foreach (TSource element1 in collection) yield return element1;
    yield return element;
}