动态添加成员到动态对象

发布于 2024-08-18 03:10:56 字数 712 浏览 1 评论 0 原文

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

当您这样做时:

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

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

我知道如何使用自定义动态对象执行此操作(实际上我 几个月前在博客中提到过),使用 DynamicObject 类的方法,但是我如何使用 any 动态对象?

我可能可以使用 IDynamicMetaObjectProvider 接口,但我不明白如何使用它。例如,我应该将什么参数传递给 GetMetaObject 方法? (它需要一个表达式

顺便问一下,如何对动态对象执行反射? “常规”反射和 TypeDescriptor 不显示动态成员...

任何见解将不胜感激!

I'm looking for a way to add members dynamically to an dynamic object. OK, I guess a little clarification is needed...

When you do that :

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

The Bar property will be added dynamically at runtime. But the code still refers "statically" to Bar (the name "Bar" is hard-coded)... What if I want to add a property at runtime without knowing its name at compile time ?

I know how to do this with a custom dynamic object (I actually blogged about it a few months ago), using the methods of the DynamicObject class, but how can I do it with any dynamic object ?

I could probably use the IDynamicMetaObjectProvider interface, but I don't understand how to use it. For instance, what argument should I pass to the GetMetaObject method ? (it expects an Expression)

And by the way, how do you perform reflection on dynamic objects ? "Regular" reflection and TypeDescriptor don't show the dynamic members...

Any insight would be appreciated !

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

与之呼应 2024-08-25 03:10:56

你想要的类似于Python的getattr/setattr函数。在 C# 或 VB.NET 中没有内置等效方法来执行此操作。 DLR 的外层(在 Microsoft.Scripting.dll 中随 IronPython 和 IronRuby 一起提供)包括一组托管 API,其中包括具有 GetMember/SetMember 方法的 ObjectOperations API。您可以使用它们,但需要 DLR 和基于 DLR 的语言的额外依赖性。

最简单的方法可能是使用现有的 C# 绑定器之一创建 CallSite。您可以通过查看 ildasm 或 Reflector 中“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);

What you want is similar to Python's getattr/setattr functions. There's no built in equivalent way to do this in C# or VB.NET. The outer layer of the DLR (which ships w/ IronPython and IronRuby in Microsoft.Scripting.dll) includes a set of hosting APIs which includes an ObjectOperations API that has GetMember/SetMember methods. You could use those but you'd need the extra dependency of the DLR and a DLR based language.

Probably the simplest approach would be to create a CallSite w/ one of the existing C# binders. You can get the code for this by looking at the result of "foo.Bar = 42" in ildasm or reflector. But a simple example of this would be:

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);
卖梦商人 2024-08-25 03:10:56

ExpandoObject 实现 IDictionary尽管明确地。这意味着您可以简单地将 ExpandoObject 转换为 IDictionary并操纵字典。

dynamic foo = new ExpandoObject();
foo.Bar = 42;
food = (IDictionary<string,object>)foo;
food["Baz"] = 54

ExpandoObject implements IDictionary<string,object> albeit explicitly. What this means is that you can simply cast the ExpandoObject to IDictionary<string,object> and manipulate the dictionary.

dynamic foo = new ExpandoObject();
foo.Bar = 42;
food = (IDictionary<string,object>)foo;
food["Baz"] = 54
单身情人 2024-08-25 03:10:56

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

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

它还可以调用许多其他类型的 C# 绑定器

The opensource framework Dynamitey will do this (available via nuget). It encapsulates while still caching the call site and binder code that @Dino-Viehland used.

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

It can also call many other kinds of c# binder too.

顾铮苏瑾 2024-08-25 03:10:56

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

I know this is quite an old post, but I thought I'd pass along Miron Abramson solution on how you can create your own type and add properties at runtime -- in case anyone else out there is looking for something similar.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文