我今天在尝试使用 FieldInfo.SetValue()
设置字段时遇到问题,将 DynamicObject
作为第二个参数传递。在我的例子中,该字段是一个 Guid
并且 DynamicObject
应该 能够将自身转换为一个(使用 TryConvert
) 但它失败并返回 ArgumentException
。
显示问题的一些代码:
// 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);
}
}
我不是很熟悉 C# 4 的整体动态性,但我觉得这应该可以工作。我做错了什么?还有其他方法吗?
最佳答案
不,这不应该工作 - 因为动态部分在您的代码结束的地方结束。编译器正在调用一个签名为
的方法void SetValue(Object obj, Object value)
该方法调用是动态的,但它只是将最终传递对 MyDynamicObj
实例的引用。该调用在执行时解析,但 SetValue
中的任何内容都不知道您要传入其引用的对象的动态特性。
基本上,您需要在代码中执行动态部分(在本例中为转换)——涉及 C# 4 编译器执行其所有技巧的部分。您必须执行该转换,然后您可以调用 SetField
。
换句话说,这有点像用XName
类型的字段调用SetField
,但传入的是一个字符串。是的,存在从 string
到 XName
的转换,但这不是 SetField
的工作。这是编译器的工作。
现在,您可以通过让编译器做一些工作来让它工作,但您仍然需要用反射做一些工作:
static void Main(string[] args)
{
dynamic myObj = new MyDynamicObj();
var test = new Test();
var testField = typeof(Test).GetField("MyField");
var method = typeof(Program)
.GetMethod("Convert", BindingFlags.Static | BindingFlags.NonPublic);
method = method.MakeGenericMethod(testField.FieldType);
object converted = method.Invoke(null, new object[] {myObj});
testField.SetValue(test, converted);
}
static T Convert<T>(dynamic input)
{
return input;
}
关于c#-4.0 - 使用 FieldInfo.SetValue 和 DynamicObject 作为参数 2,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8002609/