I'm experimenting with DynamicObject
. One of the things I try to do is setting the values of ref
/out
arguments, as shown in the code below. However, I am not able to have the values of i
and j
in Main()
set properly (even though they are set correctly in TryInvokeMember()
). Does anyone know how to call a DynamicObject
object with ref
/out
arguments and be able to retrieve the values set inside the method?
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;
}
}
Update 7/15: Microsoft claims to have fixed the issue for the next release of .NET http://connect.microsoft.com/VisualStudio/feedback/details/543101/net-4-0s-dynamicobject-doesn-t-set-ref-out-arguments
Update 9/8/2012: Tested using VS.NET 2012 with both .NET 4.0 and 4.5, confirm: it's already fixed.
This looks like it could be a bug - probably in DynamicObject
. If you add a Wrap
method to Proxy
like this:
public void Wrap(ref int x, ref int y)
{
target.Swap(ref x, ref y);
}
Then even though this is still called dynamically (i.e. the code in Main
stays the same) the code works... so at least the general "how does a dynamic object work" layer supports pass-by-reference.
I suspect if this is indeed a bug in the DLR, it may be too late to fix for .NET 4 - but it's worth reporting on Connect anyway so it can be fixed in a service pack. Alternatively, if this is a deliberate restriction/limitation, it should be clearly documented in MSDN (which it isn't at the moment, as far as I can see).
This is not a bug. As it was already said here, DynamicObject doesn't support ref and out parameters in TryInvokeMember. Everything passed to this method is treated "by value". Shortly, TryInvokeMember method simply ignores these keywords, and that is why your method doesn't work.
If you follow Jon Skeet suggestion and create your own Wrap method within a class inherited from DynamicObject, this will be a little bit different scenario. The workflow looks like this: when there is a method call for DynamicObject, C# runtime binder first looks for the method in the class itself. If it can find one, it calls this method. At this point, information about "ref" and "out" parameters is still preserved. If it can't find such a method, it calls TryInvokeMember method and simply throws out information about "ref" and "out" keywords and starts treating everyting as "by value". Remember that DynamicObject has to suport interoperability with other language, which might not have all of the C# features.
True, information about "ref" and "out" is now missing from documentation. I will add it to the next documenation update.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With