C# 使用参数名动态创建委托
大家好,我正在尝试创建一个函数,该函数动态创建一个委托,该委托的返回值和参数与作为参数接收的MethodInfo相同,这对于相同的参数名非常重要 到目前为止,我所做的是创建一个函数,该函数返回一个lambda,该lambda接收相同的参数类型,并具有与MethodInfo相同的返回值,但它没有参数名称: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
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;
}