c#-4.0 - 使用 FieldInfo.SetValue 和 DynamicObject 作为参数 2

标签 c#-4.0 dynamic

我今天在尝试使用 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,但传入的是一个字符串。是的,存在从 stringXName 的转换,但这不是 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/

相关文章:

c#-4.0 - 在 umbraco 中创建文件夹 - Umbraco 7

c# - 我应该使用哪个类将二进制数据写入缓冲区(比如字节列表)

database - 用户创建的动态数据库 - django

具有动态列的 MySQL 数据透视表查询

c# - 与继续使用 .NET Remoting 相比,将我们的应用程序迁移到 WCF 有什么好处?

c# - 合并两个集合,但仅适用于具有匹配 id 的对象

database - 寻找跨平台的小型数据库

c# - 如何在运行时决定将哪种类型作为泛型参数传递?

c++ - 在 C++ 中扩展数组

javascript - 如何将文本解析为 JavaScript?