C#4.0';动态';不';t设置ref/out参数

C#4.0';动态';不';t设置ref/out参数,c#,dynamic,pass-by-reference,C#,Dynamic,Pass By Reference,我正在试验DynamicObject。我尝试做的一件事是设置ref/out参数的值,如下面的代码所示。但是,我无法正确设置Main()中的I和j的值(即使它们在TryInvokeMember()中设置正确)。是否有人知道如何使用ref/out参数调用DynamicObject对象,并能够检索方法中设置的值 class Program { static void Main(string[] args) { dynamic proxy = new Proxy(new

我正在试验
DynamicObject
。我尝试做的一件事是设置
ref
/
out
参数的值,如下面的代码所示。但是,我无法正确设置
Main()
中的
I
j
的值(即使它们在
TryInvokeMember()
中设置正确)。是否有人知道如何使用
ref
/
out
参数调用
DynamicObject
对象,并能够检索方法中设置的值

class Program
{
    static void Main(string[] args)
    {
        dynamic proxy = new Proxy(new Target());
        int i = 10;
        int j = 20;
        proxy.Wrap(ref i, ref j);
        Console.WriteLine(i + ":" + j); // Print "10:20" while expect "20:10"
    }
}

class Proxy : DynamicObject
{
    private readonly Target target;

    public Proxy(Target target)
    {
        this.target = target;
    }

    public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result)
    {
        int i = (int) args[0];
        int j = (int) args[1];
        target.Swap(ref i, ref j);
        args[0] = i;
        args[1] = j;
        result = null;
        return true;
    }
}

class Target
{
    public void Swap(ref int i, ref int j)
    {
        int tmp = i;
        i = j;
        j = tmp;
    }
}
2015年7月更新: 微软声称已经为下一版本的.NET解决了这个问题

2012年9月8日更新:
使用VS.NET 2012对.NET 4.0和4.5进行测试,确认:它已经被修复。

长话短说,DynamicObject不支持通过引用传递,因此您想要做的事情不可能直接实现。

这看起来可能是一个bug-可能在
DynamicObject
中。如果将
Wrap
方法添加到
Proxy
中,如下所示:

public void Wrap(ref int x, ref int y)
{
    target.Swap(ref x, ref y);
}
然后,即使这仍然是动态调用的(即
Main
中的代码保持不变),代码仍然可以工作。。。因此,至少一般的“动态对象如何工作”层支持按引用传递


我怀疑,如果这确实是DLR中的一个bug,那么为.NET4修复可能为时已晚-但无论如何,它都值得报告,以便可以在service pack中修复。或者,如果这是一个故意的限制,那么应该在MSDN中清楚地记录下来(据我所知,目前还没有)。正如这里已经说过的,DynamicObject不支持TryInvokeMember中的ref和out参数。传递给此方法的所有内容都“按值”处理。很快,TryInvokeMember方法就会忽略这些关键字,这就是您的方法无法工作的原因

如果您按照Jon Skeet的建议,在继承自DynamicObject的类中创建自己的Wrap方法,这将是一个稍微不同的场景。 工作流如下所示:当有DynamicObject的方法调用时,C#runtime binder首先在类本身中查找该方法。如果它能找到一个,就调用这个方法。此时,有关“ref”和“out”参数的信息仍然保留。如果找不到这样的方法,它将调用TryInvokeMember方法,并简单地抛出关于“ref”和“out”关键字的信息,并开始将所有内容视为“按值”。 请记住,DynamicObject必须支持与其他语言的互操作性,而这些语言可能不具备所有C#特性


的确,文档中现在缺少关于“ref”和“out”的信息。我将把它添加到下一次文档更新中。

完全重复:@gabe:实际上我看到了这个问题,但这个问题是关于是否可以确定一个参数是否可以被称为passed by ref/out,这与我在这里提出的问题完全不同。在我的例子中,我对此不感兴趣,因为我可以对“Target”类进行一点思考。即使你的问题不同,这个问题的答案也包括你的问题的答案:DynamicObject是“按值调用”@gabe:我仍然不认为这可以作为提出完全不同的问题的理由“一模一样“对于另一个问题,您认为这两个问题都有一个答案:)。我在VS.Net 2010上试用了.Net 4.0,但它不起作用。有趣的解决方法,谢谢。知道这一点很好,但如果必须实现每个转发方法,显然我不会求助于DynamicObject:)。我已经按照你的建议提交了一个bug报告来连接。我不认为这是一个bug,因为它不可能工作
TryInvokeMember
获取参数的对象数组。为了将int放入数组中,必须将它们装箱,这样才能复制它们。如果调用完成后,动态绑定器将ref-args从原始args数组中复制回来,那么这可能会起到一半的作用,但这只是模拟ref-args。@gabe:当您使用反射调用带有ref参数的方法时,它就是这样工作的-正如我所说,当静态提供该方法时,即使仍在动态调用该方法,该方法仍然有效。换句话说,它在DynamicMetaObject级别工作。当然,与“true”通过引用传递相比,它会有一些纠结(例如,在方法调用过程中变量会被解除关联),但对于99%的情况,我确信这并不重要。这感觉比完全忽略它们是ref参数这一事实更好,就像现在一样。Jon:你怎么能用ref参数调用InvokeMethod?你是说如果我调用
Target.InvokeMember(“Swap”,0,null,proxy,new object[]{I,j})
,它会像预期的那样工作吗?不,不是这样:
object[]args=new object[]{I,j};InvokeMember(“Swap”,0,null,proxy,args);i=(int)args[0];j=(int)args[1]换句话说,数组在随后的反射中得到正确的值-这不是完全相同的行为,但非常接近。好信息,谢谢!然而,虽然DynamicObject不应该为互操作性而担心ref/out,但是TryInvokeMember的调用者(我从您的解释中理解为C#绑定器)应该根据TryInvokeMember中设置的args数组来尝试设置out/ref。不能吗?不是吗?