I ran into a problem today when trying to set a field using FieldInfo.SetValue() passing a DynamicObject as the second argument. In my case, the field is a Guid and the DynamicObject should be able to convert itself to a one (using TryConvert) but it fails with an ArgumentException.
Some code that shows the problem:
// Simple impl of a DynamicObject to prove point
public class MyDynamicObj : DynamicObject
{
public override bool TryConvert(ConvertBinder binder, out object result)
{
result = null;
// Support converting this to a Guid
if (binder.Type == typeof(Guid))
{
result = Guid.NewGuid();
return true;
}
return false;
}
}
public class Test
{
public Guid MyField;
}
class Program
{
static void Main(string[] args)
{
dynamic myObj = new MyDynamicObj();
// This conversion works just fine
Guid guid = myObj;
var test = new Test();
var testField = typeof(Test).GetField("MyField");
// This, however, fails with:
// System.ArgumentException
// Object of type 'ConsoleApplication1.MyDynamicObj' cannot be converted to type 'System.Guid'.
testField.SetValue(test, myObj);
}
}
I’m not very familiar with the whole dynamicness of C# 4, but this felt to me like something that should work.. What am I doing wrong? Is there another way of doing this?
No, this shouldn’t work – because the dynamic portion ends where your code ends. The compiler is calling a method with a signature of
That method call is dynamic, but it’s just going to end up passing in a reference to the instance of
MyDynamicObj. The call is resolved at execution time, but nothing inSetValueknows anything about the dynamic nature of the object whose reference you’re passing in.Basically you need to perform the dynamic part (the conversion in this case) in your code – the bit that involves the C# 4 compiler doing all its tricks. You’ve got to perform that conversion, and then you can call
SetField.To put it another way – it’s a bit like calling
SetFieldwith a field of typeXName, but passing in a string. Yes, there’s a conversion fromstringtoXName, but it’s notSetField‘s job to work that out. That’s the compiler’s job.Now, you can get this to work by making the compiler do some of the work, but you still need to do some with reflection: