使用DLR使用ref参数调用方法

时间:2015-04-24 16:27:30

标签: c# dynamic

尝试使用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)可能是动态的。

2 个答案:

答案 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。因此,显然尝试使用表达式也是行不通的。