8

我正在寻找一种将成员动态添加到动态对象的方法。好的,我想需要澄清一下...

当你这样做时:

dynamic foo = new ExpandoObject();
foo.Bar = 42;

Bar属性将在运行时动态添加。但是代码仍然“静态地”引用 Bar(名称“Bar”是硬编码的)......如果我想在运行时添加一个属性而不知道它在编译时的名称怎么办?

我知道如何使用类的方法来使用自定义动态对象(实际上几个月前我在博客上写过DynamicObject) ,但是如何使用任何动态对象来做到这一点?

我可能可以使用该IDynamicMetaObjectProvider界面,但我不明白如何使用它。例如,我应该将什么参数传递给GetMetaObject方法?(它期望一个Expression

顺便说一句,你如何对动态对象进行反射?“常规”反射并且TypeDescriptor不显示动态成员......

任何见解将不胜感激!

4

4 回答 4

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);
于 2010-01-17T09:47:14.810 回答
5

开源框架Dynamitey将执行此操作(可通过nuget 获得)。它封装同时仍缓存@Dino-Viehland 使用的调用站点和绑定器代码。

Dynamic.InvokeSet(foo,"Bar",42);

它也可以调用许多其他类型的 c# binder

于 2011-07-06T19:49:31.020 回答
5

ExpandoObject 实现 IDictionary<string,object> 尽管是显式的。这意味着您可以简单地将 ExpandoObject 转换为 IDictionary<string,object> 并操作字典。

dynamic foo = new ExpandoObject();
foo.Bar = 42;
food = (IDictionary<string,object>)foo;
food["Baz"] = 54
于 2011-08-12T22:24:08.157 回答
1

我知道这是一篇相当老的帖子,但我想我会传递Miron Abramson 解决方案,介绍如何创建自己的类型并在运行时添加属性——以防其他人正在寻找类似的东西。

于 2012-03-28T22:38:25.070 回答