尝试使用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
)可能是动态的。
答案 0 :(得分:1)
我重现了您的问题,并发现了相关代码的一些潜在问题。为了解释,我将从如何解释你实际上想要做的事情开始,运行以下代码:
dynamic program = ...;
program.RefTest(ref myInt);
请注意,上面的代码运行正常并运行该方法。
这里需要注意的一些事项:
program
变量是常量。void
您问题中与此不符的一些内容是:
Expression.Dynamic
调用告诉方法返回object
。相反,它应该返回typeof(void)
。Expression.Lambda
来电将委托类型指定为Action<int>
。参数应为ref int
类型。要解决此问题,应该有Action
代替ref
参数。 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);
但是,我得到了与你相同的例外:
发生了'Microsoft.CSharp.RuntimeBinder.RuntimeBinderException'类型的未处理异常 System.Core.dll
附加信息:无法将类型'int'转换为'ref int'
这让我相信存在一些框架错误导致RuntimeBinder
错误地处理动态调用的ref
参数,或者Expression.Dynamic
代码错误地通过值参数分配{应使用{1}}参数。
请注意,我也能够重现ref
参数的问题,从而产生完全相同的结果。
但是,对于您的情况,您似乎已经了解了要调用的类型,甚至创建了一个强类型的委托来调用。在这种情况下,我会使用以下内容:
out
答案 1 :(得分:0)
如果我没错,Dynamic doesn't support ref/out parameters。参考 Alexandra Rusina在链接主题和here also中的答案。
尝试以下(不会编译):
dynamic value = 5;
RefTest(ref value);
简单动态不支持ref / out。因此,显然尝试使用表达式也是行不通的。