我正在寻找一种动态添加成员到动态对象的方法。好的,我想还需要一点澄清......
当你这样做时:
dynamic foo = new ExpandoObject();
foo.Bar = 42;
Bar
属性将在运行时动态添加。但是代码仍然“静态地”引用到Bar(名称“Bar”是硬编码的)...如果我想在运行时添加属性而不知道它在编译时的名称会怎样?
我知道如何使用DynamicObject
类的方法使用自定义动态对象(我实际上是blogged about it几个月前),但是如何使用任何动态对象?
我可以使用IDynamicMetaObjectProvider
界面,但我不明白如何使用它。例如,我应该将哪个参数传递给GetMetaObject
方法? (它需要Expression
)
顺便说一句,你如何对动态对象进行反射? “常规”反射和TypeDescriptor
不显示动态成员......
任何见解都将受到赞赏!
答案 0 :(得分:9)
你想要的是类似于Python的getattr / setattr函数。在C#或VB.NET中没有内置的等效方法。 DLR的外层(在Microsoft.Scripting.dll中附带IronPython和IronRuby)包含一组托管API,其中包括具有GetMember / SetMember方法的ObjectOperations API。您可以使用这些,但您需要DLR和基于DLR的语言的额外依赖。
可能最简单的方法是创建一个带有现有C#绑定器的CallSite。您可以通过查看ildasm或反射器中“foo.Bar = 42”的结果来获取此代码。但一个简单的例子就是:
object x = new ExpandoObject();
CallSite<Func<CallSite, object, object, object>> site = CallSite<Func<CallSite, object, object, object>>.Create(
Binder.SetMember(
Microsoft.CSharp.RuntimeBinder.CSharpBinderFlags.None,
"Foo",
null,
new[] { CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null) }
)
);
site.Target(site, x, 42);
Console.WriteLine(((dynamic)x).Foo);
答案 1 :(得分:5)
开源框架Dynamitey将执行此操作(可通过nuget获得)。它封装了同时仍然缓存@ Dino-Viehland使用的调用站点和绑定器代码。
Dynamic.InvokeSet(foo,"Bar",42);
它也可以调用许多other kinds of c# binder too。
答案 2 :(得分:5)
ExpandoObject实现IDictionary&lt; string,object&gt;虽然明确。这意味着您可以简单地将ExpandoObject强制转换为IDictionary&lt; string,object&gt;并操纵字典。
dynamic foo = new ExpandoObject();
foo.Bar = 42;
food = (IDictionary<string,object>)foo;
food["Baz"] = 54
答案 3 :(得分:1)
我知道这是一个很老的帖子,但我想我会传递Miron Abramson solution关于如何创建自己的类型并在运行时添加属性 - 以防其他人在那里寻找某些东西类似。