ExpandoObject,DynamicObject和dynamic之间的区别

System.Dynamic.ExpandoObjectSystem.Dynamic.DynamicObjectdynamic之间有什么区别?

你在哪些情况下使用这些types?

dynamic关键字用于声明应该迟到的variables。
如果你想使用后期绑定,对于任何真实或想象的types,你使用dynamic关键字,编译器做其余的。

当您使用dynamic关键字与普通实例进行交互时, DLR会对实例的常规方法执行后期绑定调用。

IDynamicMetaObjectProvider接口允许类控制其后期绑定行为。
当您使用dynamic关键字与IDynamicMetaObjectProvider实现进行交互时,DLR将调用IDynamicMetaObjectProvider方法, IDynamicMetaObjectProvider对象本身决定要执行的操作。

ExpandoObjectDynamicObject类是IDynamicMetaObjectProvider实现。

ExpandoObject是一个简单的类,允许您将成员添加到实例并使用它们的dynamic盟友。
DynamicObject是一个更高级的实现,它可以被inheritance来轻松地提供自定义的行为。

根据C#语言规范dynamic是一个types声明。 即dynamic x表示variablesx具有dynamictypes。

DynamicObject是一种可以轻松实现IDynamicMetaObjectProvider的types,因此可以覆盖该types的特定绑定行为。

ExpandoObject是一种类似于物业包的types。 也就是说,您可以在运行时将属性,方法等添加到此types的dynamic实例中。

我将尝试为这个问题提供一个更清晰的答案,以清楚地解释dynamic, ExpandoObjectDynamicObject之间的区别。

很快, dynamic是一个关键字。 这不是一个types的本身。 它是一个关键字,它告诉编译器在devise时忽略静态types检查,而是在运行时使用后期绑定。 所以我们不会在这个答案的其余部分花费很多时间在dynamic的。

ExpandoObjectDynamicObject确实是types。 在表面上,他们看起来非常相似。 这两个类都实现了IDynamicMetaObjectProvider 。 但是,深入挖掘,你会发现它们根本不相似。

DynamicObject是IDynamicMetaObjectProvider的部分实现,纯粹意味着开发人员可以实现自己的自定义types,支持具有自定义底层存储和检索行为的dynamic分派以使dynamic分派工作。

  1. DynamicObject不能直接构造。
  2. 您必须扩展DynamicObject才能使其作为开发人员使用。
  3. 扩展dynamic对象时,您现在可以提供有关如何在运行时dynamic分派parsing内部存储在基础数据表示中的数据的CUSTOM行为。
  4. ExpandoObject将基础数据存储在Dictionary等中。如果实现DynamicObject,则可以将数据存储在任何地方,无论您喜欢什么。 (例如,如何获取和设置调度数据完全取决于您)。

简而言之,当您想要创build可以与DLR一起使用的OWNtypes并使用任何您想要的自定义行为时,请使用DynamicObject。

示例:假设您希望有一个dynamictypes,当试图对不存在的成员进行get(即,在运行时未添加)时返回一个自定义默认值。 而这个默认会说,“对不起,这个jar子里没有cookies!”。 如果你想要一个像这样的dynamic对象,你需要控制没有find字段时会发生什么。 ExpandoObject不会让你这样做。 所以你需要用独特的dynamic成员parsing(调度)行为来创build自己的types,并使用它来代替现成的ExpandoObject

你可以创build一个types如下:(注意,下面的代码只是为了说明而不能运行,要学习如何正确使用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; } } 

现在,我们可以使用这个我们刚刚创build的虚构类作为一个dynamictypes,如果该字段不存在,这个dynamictypes将具有非常自定义的行为。

 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!") 

ExpandoObjectIDynamicMetaObjectProvider的完整实现,.NET框架团队已经为您做出所有这些决定。 如果您不需要任何自定义行为,那么这非常有用,并且您认为ExpandoObject对您来说足够好(90%的时间, ExpandoObject足够好)。 因此,例如,请参阅以下内容,对于ExpandoObject,如果dynamic成员不存在,devise人员将select抛出exception。

 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只是一种预先select的方式来扩展dynamic对象的某些dynamic调度行为,可能会为你工作 ,但可能不取决于你的特定需求。

DyanmicObject是一个帮助者BaseType,它使得用独特的dynamic行为实现你自己的types变得简单而容易。

上面很多示例源代码都是基于这个有用的教程。