[英]Use DLR to invoke a method with ref parameter
尝试调用带有ref参数的示例方法:
public void RefTest(ref int i)
{
Console.WriteLine(i);
i = 18;
}
使用DLR:
var prog = new Program();
var binder = Microsoft.CSharp.RuntimeBinder.Binder.InvokeMember(
CSharpBinderFlags.ResultDiscarded,
"RefTest", null, typeof(Program),
new CSharpArgumentInfo[]{
CSharpArgumentInfo.Create(0,null),
CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.IsRef,null)
}
);
ParameterExpression p = Expression.Parameter(typeof(int));
Expression dyn = Expression.Dynamic(binder, typeof(object), Expression.Constant(prog), p);
var lam = Expression.Lambda<Action<int>>(dyn, p).Compile();
lam(9); //RuntimeBinderException
但是,代码由于RuntimeBinderException失败而无法将int转换为ref int。 如何解决?
我正在尝试模仿以下代码:
dynamic prog = new Program();
Action<int> lam = i => prog.RefTest(ref i);
lam(9);
我必须使用DLR而不是反射,因为提供的对象( prog
)可能是动态的。
我转载了您的问题,并发现了相关代码中的一些潜在问题。 为了说明,我将从解释您实际尝试做的事情开始,运行以下代码:
dynamic program = ...;
program.RefTest(ref myInt);
请注意,上面的代码可以正常工作并运行该方法。
这里需要注意的几件事:
program
变量是一个常数。 void
您的问题中有一些与此不符的事情是:
Expression.Dynamic
调用告诉该方法返回object
。 相反,它应该返回typeof(void)
。 Expression.Lambda
调用将委托类型指定为Action<int>
。 该参数应为ref int
类型。 为了解决这个问题,应该有一个具有ref
参数的Action
。 delegate void RefAction<T>(ref T arg1)
这将我带到以下代码:
Expression programExpr = Expression.Constant(program);
var binder = Binder.InvokeMember(CSharpBinderFlags.ResultDiscarded | CSharpBinderFlags.InvokeSimpleName, "Bla", null, typeof (Program),
new[] { CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null),
CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.IsRef, null) });
var intParam = Expression.Parameter(typeof (int).MakeByRefType(), "x");
Expression methodCall = Expression.Dynamic(binder, typeof (void), programExpr, intParam);
var expr = Expression.Lambda<RefAction<int>>(methodCall, intParam).Compile();
expr(ref myInt);
但是,我得到与您相同的例外:
System.Core.dll中发生了类型为“ Microsoft.CSharp.RuntimeBinder.RuntimeBinderException”的未处理异常
附加信息:无法将类型'int'转换为'ref int'
这使我相信存在一些框架错误,该错误会导致RuntimeBinder
错误地处理用于动态调用的ref
参数,或者Expression.Dynamic
代码错误地通过应使用ref
参数的值参数来分配。
请注意,我也能够重现out
参数的问题,从而得到完全相同的结果。
但是,对于您而言,您似乎已经对要调用的类型非常了解,甚至创建了要调用的强类型委托。 在这种情况下,我将遵循以下条件:
var programExpr = Expression.Constant(program);
var intParam = Expression.Parameter(typeof(int).MakeByRefType(), "x");
var methodCall = Expression.Call(programExpr, typeof (Program)
.GetMethod("RefTest", BindingFlags.NonPublic | BindingFlags.Instance), intParam);
var expr = Expression.Lambda<RefAction<int>>(methodCall, intParam).Compile();
expr(ref myInt);
如果我没看错, Dynamic不支持ref / out参数 。 请在链接的线程中以及此处查阅 Alexandra Rusina的答案。
请尝试以下操作(无法编译):
dynamic value = 5;
RefTest(ref value);
只是动态不支持参考/输出。 因此,显然对表达式进行相同的尝试也将不起作用。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.