簡體   English   中英

當您在另一個變量中有名稱時,如何設置 C# 4 動態 object 的屬性

[英]How to set a property of a C# 4 dynamic object when you have the name in another variable

我正在尋找一種方法來修改dynamic C# 4.0 object 上的屬性,其屬性名稱僅在運行時已知。

有沒有辦法做類似的事情( ExpandoObject僅用作示例,這可以是實現IDynamicMetaObjectProvider的任何 class ):

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

這相當於:

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

還是反思是唯一的出路?

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

不是很容易,沒有。 反射不起作用,因為它假設一個常規類型模型,這不是 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上使用,並針對動態和非動態場景進行了大量優化。

要添加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);
    }
}

我的開源框架Dynamitey具有使用DLR基於字符串名稱進行調用的方法。 它完成緩存綁定站點的工作,並將其簡化為一個方法調用。 它也比非動態對象上的反射運行得更快。

Dynamic.InvokeSet(e, "TestKey", "value");

快速成員可能適合賬單 - 它看起來像是在運行中生成IL,但是緩存它所以它在第一次使用后真的很快。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM