繁体   English   中英

使用DLR调用带有ref参数的方法

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM