ExpandoObject、DynamicObject 和 dynamic 的区别
Posted
技术标签:
【中文标题】ExpandoObject、DynamicObject 和 dynamic 的区别【英文标题】:Differences between ExpandoObject, DynamicObject and dynamic 【发布时间】:2011-04-03 16:32:41 【问题描述】:System.Dynamic.ExpandoObject
、System.Dynamic.DynamicObject
和dynamic
有什么区别?
您在哪些情况下使用这些类型?
【问题讨论】:
【参考方案1】:dynamic
关键字用于声明应为后期绑定的变量。
如果您想对任何真实或想象的类型使用后期绑定,请使用 dynamic
关键字,编译器会完成剩下的工作。
当您使用 dynamic
关键字与普通实例交互时,DLR 会执行对实例普通方法的后期绑定调用。
IDynamicMetaObjectProvider
interface 允许类控制其后期绑定行为。
当您使用 dynamic
关键字与 IDynamicMetaObjectProvider
实现进行交互时,DLR 会调用 IDynamicMetaObjectProvider
方法,而对象本身会决定要做什么。
ExpandoObject
和 DynamicObject
类是 IDynamicMetaObjectProvider
的实现。
ExpandoObject
是一个简单的类,它允许您向实例添加成员并使用它们dynamic
ally。DynamicObject
是一个更高级的实现,可以继承它以轻松提供自定义行为。
【讨论】:
什么是了解更多信息的好地方?不是 API,而是 API 背后的原因?例如为什么 ExpandoObject 不是从 DynamicObject 派生的,它看起来是基于 ruby 的“method_missing”编程的事实上的基本类型。 您能否在可能的情况下添加一些使用示例?例如,我将如何使用 DynamicObject,有什么好处? 没有像这样的例子的好答案就像没有奶油的蛋糕。 对于 Expando blogs.msdn.microsoft.com/csharpfaq/2009/09/30/… 对于 dynamicObject blogs.msdn.microsoft.com/csharpfaq/2009/10/19/…【参考方案2】:我将尝试为这个问题提供更清晰的答案,以清楚地解释动态 ExpandoObject
和 DynamicObject
之间的区别。
很快,dynamic
是一个关键字。它本身不是一种类型。它是一个关键字,告诉编译器在设计时忽略静态类型检查,而在运行时使用后期绑定。因此,在此答案的其余部分中,我们不会在 dynamic
上花费太多时间。
ExpandoObject
和 DynamicObject
确实是类型。在 SURFACE 上,它们看起来非常相似。这两个类都实现了IDynamicMetaObjectProvider
。然而,深入挖掘,你会发现它们根本不相似。
DynamicObject 是IDynamicMetaObjectProvider
的部分实现,纯粹是为了让开发人员实现他们自己的支持动态调度的自定义类型以及自定义底层存储和检索行为以使动态调度工作的起点。
-
DynamicObject 无法直接构造。
您必须扩展 DynamicObject 才能让您作为开发人员使用它。
当您扩展 DynamicObject 时,您现在可以提供 CUSTOM 行为,说明您希望动态调度如何解析为运行时在底层数据表示中内部存储的数据。
ExpandoObject 将基础数据存储在字典等中。如果您实现 DynamicObject,您可以随心所欲地存储数据。 (例如,您如何获取和设置调度数据完全取决于您)。
简而言之,当您想要创建可与 DLR 一起使用的 OWN 类型并使用您喜欢的任何 CUSTOM 行为时,请使用 DynamicObject。
示例:假设您希望有一个动态类型,该类型在尝试获取不存在的成员(即在运行时未添加)时返回自定义默认值。该默认设置会说,“对不起,这个罐子里没有饼干!”。如果您想要一个具有这样行为的动态对象,则需要控制未找到字段时发生的情况。 ExpandoObject 不会让您这样做。因此,您需要使用独特的动态成员解析(调度)行为创建自己的类型,并使用它而不是现成的ExpandoObject
。
您可以按如下方式创建类型:(注意,以下代码仅用于说明,可能无法运行。要了解如何正确使用DynamicObject,其他地方有很多文章和教程。)
public class MyNoCookiesInTheJarDynamicObject : DynamicObject
Dictionary<string, object> properties = new Dictionary<string, object>();
public override bool TryGetMember(GetMemberBinder binder, out object result)
if (properties.ContainsKey(binder.Name))
result = properties[binder.Name];
return true;
else
result = "I'm sorry, there are no cookies in this jar!"; //<-- THIS IS OUR
CUSTOM "NO COOKIES IN THE JAR" RESPONSE FROM OUR DYNAMIC TYPE WHEN AN UNKNOWN FIELD IS ACCESSED
return false;
public override bool TrySetMember(SetMemberBinder binder, object value)
properties[binder.Name] = value;
return true;
public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result)
dynamic method = properties[binder.Name];
result = method(args[0].ToString(), args[1].ToString());
return true;
现在,我们可以将刚刚创建的这个虚构类用作动态类型,如果该字段不存在,该类具有非常自定义的行为。
dynamic d = new MyNoCookiesInTheJarDynamicObject();
var s = d.FieldThatDoesntExist;
//in our contrived example, the below should evaluate to true
Assert.IsTrue(s == "I'm sorry, there are no cookies in this jar!")
ExpandoObject
是IDynamicMetaObjectProvider
的完整实现,.NET Framework 团队已为您做出所有这些决定。如果您不需要任何自定义行为,并且您觉得 ExpandoObject 对您来说足够好(90% 的时间,ExpandoObject
足够好),这将非常有用。因此,例如,请参见以下内容,对于 ExpandoObject,设计人员选择在动态成员不存在时抛出异常。
dynamic d = new ExpandoObject();
/*
The ExpandoObject designers chose that this operation should result in an
Exception. They did not have to make that choice, null could
have been returned, for example; or the designers could've returned a "sorry no cookies in the jar" response like in our custom class. However, if you choose to use
ExpandoObject, you have chosen to go with their particular implementation
of DynamicObject behavior.
*/
try
var s = d.FieldThatDoesntExist;
catch(RuntimeBinderException) ...
总而言之,ExpandoObject
只是一种预先选择的方法,可以使用某些可能适合您的动态调度行为来扩展 DynamicObject,但可能不取决于您的特定需求。 p>
而 DyanmicObject
是一个辅助 BaseType,它使您可以轻松轻松地实现具有独特动态行为的类型。
A useful tutorial on which much of the example source above is based.
【讨论】:
很好的解释。只是一项技术更正:ExpandoObject 不继承自 DynamicObject。 对DynamicObject
示例的小修正:当覆盖TryGetMember
时,如果您返回false,则在尝试访问不存在的属性时将抛出RuntimeBinderException
。要使 sn-p 实际工作,您应该返回 true
。
如果 *** 的所有答案都和你的一样,世界会变得更美好。惊人的解释。【参考方案3】:
根据 C# 语言规范dynamic
是一个类型声明。 IE。 dynamic x
表示变量x
的类型为dynamic
。
DynamicObject
是一种易于实现 IDynamicMetaObjectProvider
并因此覆盖该类型的特定绑定行为的类型。
ExpandoObject
是一种类似于属性包的类型。 IE。您可以在运行时向此类型的动态实例添加属性、方法等。
【讨论】:
dynamic
不是实际类型...这只是告诉编译器对此变量使用后期绑定的提示。 dynamic
变量实际上在 MSIL 中声明为 object
@Thomas:从编译器的角度来看,它是一种类型,但运行时表示是 Object 的表示是对的。您会在几个 MS 演示文稿中找到“静态类型为动态”的陈述。
@Thomas:语言规范说“C# 4.0 引入了一种称为动态的新静态类型”。
确实...但我认为将其视为一种类型会令人困惑,因为与 DynamicObject 或 ExpandoObject 等类型没有继承关系
@NathanA 我和你在一起。但是,语言规范将其称为类型,所以这就是我要使用的。【参考方案4】:
上面DynamicObject
的例子并没有说清楚区别,因为它基本上实现了ExpandoObject
已经提供的功能。
在下面提到的两个链接中,很明显在DynamicObject
的帮助下,可以保留/更改实际类型(在下面链接中使用的示例中为XElement
)并更好地控制属性和方法。
https://blogs.msdn.microsoft.com/csharpfaq/2009/09/30/dynamic-in-c-4-0-introducing-the-expandoobject/
https://blogs.msdn.microsoft.com/csharpfaq/2009/10/19/dynamic-in-c-4-0-creating-wrappers-with-dynamicobject/
public class DynamicXMLNode : DynamicObject
XElement node;
public DynamicXMLNode(XElement node)
this.node = node;
public DynamicXMLNode()
public DynamicXMLNode(String name)
node = new XElement(name);
public override bool TrySetMember(SetMemberBinder binder, object value)
XElement setNode = node.Element(binder.Name);
if (setNode != null)
setNode.SetValue(value);
else
if (value.GetType() == typeof(DynamicXMLNode))
node.Add(new XElement(binder.Name));
else
node.Add(new XElement(binder.Name, value));
return true;
public override bool TryGetMember(GetMemberBinder binder, out object result)
XElement getNode = node.Element(binder.Name);
if (getNode != null)
result = new DynamicXMLNode(getNode);
return true;
else
result = null;
return false;
【讨论】:
以上是关于ExpandoObject、DynamicObject 和 dynamic 的区别的主要内容,如果未能解决你的问题,请参考以下文章
ExpandoObject、DynamicObject 和 dynamic 的区别
如何使用 ServiceStack JsonSerializer 序列化 ExpandoObject?