当您在另一个变量中具有名称时,如何设置C#4动态对象的属性

Kie*_*ton 43 .net c# reflection dynamic

我正在寻找一种方法来修改dynamicC#4.0对象上的属性,其属性名称仅在运行时已知.

有没有办法做某些事情(ExpandoObject仅用作示例,这可能是任何实现的类IDynamicMetaObjectProvider):

string key = "TestKey";
dynamic e = new ExpandoObject();
e[key] = "value";
Run Code Online (Sandbox Code Playgroud)

这相当于:

dynamic e = new ExpandoObject();
e.TestKey = "value";
Run Code Online (Sandbox Code Playgroud)

或者是前进反思的唯一途径?

Jon*_*esø 60

Paul Sasik在C#4.0 Dynamic vs Expando上回答了类似的问题......他们在哪里适合?

using System;
using System.Dynamic;

class Program
{
    static void Main(string[] args)
    {
        dynamic expando = new ExpandoObject();
        var p = expando as IDictionary<String, object>;
        p["A"] = "New val 1";
        p["B"] = "New val 2";

        Console.WriteLine(expando.A);
        Console.WriteLine(expando.B);
    }
}
Run Code Online (Sandbox Code Playgroud)


Mar*_*ell 16

不是很容易,没有.反射不起作用,因为它假定一个常规类型模型,而不是全范围模型dynamic.如果你实际上只是在谈论常规对象,那么只需在这里使用反射.否则,我希望您可能需要对编译器为基本分配发出的代码进行反向工程,并将其调整为具有灵活的成员名称.不过我会说实话:这不是一个有吸引力的选择; 一个简单的:

dynamic foo = ...
foo.Bar = "abc";
Run Code Online (Sandbox Code Playgroud)

翻译为:

if (<Main>o__SiteContainer0.<>p__Site1 == null)
{
    <Main>o__SiteContainer0.<>p__Site1 = CallSite<Func<CallSite, object, string, object>>.Create(Binder.SetMember(CSharpBinderFlags.None, "Bar", typeof(Program), new CSharpArgumentInfo[] { CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null), CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.Constant | CSharpArgumentInfoFlags.UseCompileTimeType, null) }));
}
<Main>o__SiteContainer0.<>p__Site1.Target(<Main>o__SiteContainer0.<>p__Site1, foo, "abc");
Run Code Online (Sandbox Code Playgroud)

如果您想要一种适用于动态和非动态对象的方法:FastMember对此非常方便,可以在类型或对象级别工作:

// could be static or DLR 
var wrapped = ObjectAccessor.Create(obj); 
string propName = // something known only at runtime 
Console.WriteLine(wrapped[propName]);
Run Code Online (Sandbox Code Playgroud)

可在Nuget上使用,并针对动态和非动态场景进行了大量优化.


Jaz*_*mov 9

要添加Jonas的答案,您不必创建新的var p.改为使用这种方法:

using System;
using System.Dynamic;

class Program
{
    static void Main(string[] args)
    {
        dynamic expando = new ExpandoObject();
        ((IDictionary<String, object>)expando)["A"] = "New val 1";
        ((IDictionary<String, object>)expando)["B"] = "New val 2";

        Console.WriteLine(expando.A);
        Console.WriteLine(expando.B);
    }
}
Run Code Online (Sandbox Code Playgroud)


jbt*_*ule 5

我的开源框架Dynamitey具有使用DLR基于字符串名称进行调用的方法.它完成缓存绑定站点的工作,并将其简化为一个方法调用.它也比非动态对象上的反射运行得更快.

Dynamic.InvokeSet(e, "TestKey", "value");
Run Code Online (Sandbox Code Playgroud)