将成员动态添加到动态对象
Posted
技术标签:
【中文标题】将成员动态添加到动态对象【英文标题】:Dynamically adding members to a dynamic object 【发布时间】:2011-01-05 23:55:45 【问题描述】:我正在寻找一种的方法。好的,我想需要澄清一下...
当你这样做时:
dynamic foo = new ExpandoObject();
foo.Bar = 42;
Bar
属性将在运行时动态添加。但是代码仍然“静态地”引用 Bar(名称“Bar”是硬编码的)......如果我想在运行时添加一个属性而不知道它在编译时的名称怎么办?
我知道如何使用DynamicObject
类的方法使用自定义动态对象(实际上是几个月前的blogged about it)来做到这一点,但是我该如何使用any 动态对象?
我可能可以使用IDynamicMetaObjectProvider
接口,但我不明白如何使用它。例如,我应该将什么参数传递给 GetMetaObject
方法? (它需要一个Expression
)
顺便问一下,你如何对动态对象进行反射? “常规”反射和TypeDescriptor
不显示动态成员...
任何见解将不胜感激!
【问题讨论】:
在 C# 6.0 中,可能是你可以写成foo.$Bar = 42;
:) 不确定是否允许动态...
@nawfal,实际上,该功能已被删除......但无论如何,foo.$Bar
只是foo["Bar"]
的简写
Thomas,不知道这个功能被删除了(我很高兴),但是哦,是的,有一刻我忽略了你的 q 的真正要求。
【参考方案1】:
你想要的类似于 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);
【讨论】:
我需要花一些时间来确保我真的理解这段代码在做什么,但无论如何它工作正常......谢谢! 是否可以使用 DLR 执行此操作 上面的方法应该不能正常工作。 Setter 调用站点需要提供 2 个参数信息而不是 1 个。正确的定义是:new[] CSharpArgumentInfoFlags.None, null), CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null) 【参考方案2】:ExpandoObject 实现了 IDictionary
dynamic foo = new ExpandoObject();
foo.Bar = 42;
food = (IDictionary<string,object>)foo;
food["Baz"] = 54
【讨论】:
谢谢!正如我后来意识到的那样,ExpandoObject 确实实现了 IDictionary,因此在这种情况下它显然是最简单的解决方案。然而,我的问题范围更广:我正在寻找一种适用于任何动态对象的解决方案,而不仅仅是 ExpandoObject【参考方案3】:开源框架Dynamitey 将执行此操作(可通过nuget 获得)。它封装同时仍然缓存@Dino-Viehland 使用的调用站点和绑定代码。
Dynamic.InvokeSet(foo,"Bar",42);
也可以调用多个other kinds of c# binder too。
【讨论】:
【参考方案4】:我知道这是一篇相当老的帖子,但我想我会传递Miron Abramson solution 来介绍如何在运行时创建自己的类型和添加属性——以防其他人正在寻找类似的东西。
【讨论】:
以上是关于将成员动态添加到动态对象的主要内容,如果未能解决你的问题,请参考以下文章