.net-当您在另一个变量中使用名称时,如何设置C#4动态对象的属性

我正在寻找一种使用仅在运行时已知的属性名称来修改ExpandoObject C#4.0对象上的属性的方法。

有没有办法做类似的事情(仅以ExpandoObject为例,这可以是实现IDynamicMetaObjectProvider的任何类):

string key = "TestKey";
dynamic e = new ExpandoObject();
e[key] = "value";

相当于:

dynamic e = new ExpandoObject();
e.TestKey = "value";

还是向前反思的唯一途径?

Kieran Benton asked 2020-07-30T05:22:49Z
5个解决方案
60 votes

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);
    }
}
Jonas Follesø answered 2020-07-30T05:23:50Z
16 votes

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

dynamic foo = ...
foo.Bar = "abc";

转换为:

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");

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

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

在Nuget上可用,并针对动态和非动态方案进行了优化。

Marc Gravell answered 2020-07-30T05:23:30Z
9 votes

要添加到乔纳斯的答案中,您不必创建新的变量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);
    }
}
Jazimov answered 2020-07-30T05:24:10Z
5 votes

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

Dynamic.InvokeSet(e, "TestKey", "value");
jbtule answered 2020-07-30T05:24:31Z
0 votes

快速成员可能符合要求-看起来它可以动态生成IL,但可以对其进行缓存,因此在首次使用后确实非常快。

Marc Clifton answered 2020-07-30T05:24:51Z
translate from https://stackoverflow.com:/questions/3033410/how-to-set-a-property-of-a-c-sharp-4-dynamic-object-when-you-have-the-name-in-an