ExpandoObject,DynamicObject和dynamic之间的差异

M4N*_*M4N 162 .net c# dynamic expandoobject dynamicobject

之间有什么区别System.Dynamic.ExpandoObject,System.Dynamic.DynamicObjectdynamic

在哪些情况下你使用这些类型?

SLa*_*aks 142

dynamic关键字用于声明应该是后期绑定的变量.
如果你想使用后期绑定,对于任何真实或想象的类型,你使用dynamic关键字,编译器完成剩下的工作.

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

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

ExpandoObjectDynamicObject类的实现IDynamicMetaObjectProvider.

ExpandoObject是一个简单的类,它允许您将成员添加到实例并使用它们dynamic.
DynamicObject是一种更高级的实现,可以继承以轻松提供自定义行为.

  • 没有像这样的例子的好答案就像没有奶油的蛋糕. (10认同)
  • 你能在可能的地方添加一些用法示例吗?例如,我将如何使用DynamicObject,有什么好处? (4认同)
  • 什么是了解更多相关信息的好地方?不是API而是API背后的原因?例如,为什么ExpandoObject不是从DynamicObject派生的,它看起来是基于ruby的'method_missing'编程的事实基类型. (2认同)

Ayo*_*o I 56

我将尝试为这个问题提供一个更清晰的答案,清楚地解释动态ExpandoObjectDynamicObject.之间的差异.

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

ExpandoObject并且DynamicObject确实类型.在SURFACE上,它们看起来非常相似.两个类都实现IDynamicMetaObjectProvider.然而,深入挖掘,你会发现它们根本不相似.

DynamicObject是一个部分实现,IDynamicMetaObjectProvider纯粹意味着开发人员可以实现自己的自定义类型,支持动态调度和自定义底层存储和检索行为,以实现动态调度工作.

  1. 无法直接构造DynamicObject.
  2. 您必须扩展DynamicObject,以便它作为开发人员对您有用.
  3. 扩展DynamicObject时,您现在可以提供有关如何在运行时将动态分派解析为内部存储在基础数据表示中的数据的CUSTOM行为.
  4. ExpandoObject将基础数据存储在Dictionary等中.如果实现DynamicObject,则可以随时随地存储数据.(例如,如何获取和设置调度数据完全取决于您).

简而言之,当您想要创建可与DLR一起使用的OWN类型并使用您想要的任何CUSTOM行为时,请使用DynamicObject.

示例:假设您想要一个动态类型,只要在不存在的成员上尝试获取(即在运行时尚未添加),就会返回自定义默认值.那个默认会说,"对不起,这个罐子里没有饼干!".如果您想要一个行为类似的动态对象,则需要控制未找到字段时发生的情况.ExpandoObject不允许你这样做.因此,您需要使用独特的动态成员解析(dispatch)行为创建自己的类型,并使用它而不是现成的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;
    }
}
Run Code Online (Sandbox Code Playgroud)

现在,我们可以使用我们刚创建的这个虚构类作为动态类型,如果该字段不存在则具有非常自定义的行为.

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!")
Run Code Online (Sandbox Code Playgroud)

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) { ... }
Run Code Online (Sandbox Code Playgroud)

总而言之,ExpandoObject只是一种预先选择的方式来扩展DynamicObject,其中某些动态调度行为可能对您有用,但可能不依赖于您的特定需求.

然而,DyanmicObject是一个帮助程序BaseType,它使简单易用的独特动态行为实现您自己的类型.

一个有用的教程,上面的大部分示例源都是基于此.


Bri*_*sen 35

根据C#语言规范dynamic是一种类型声明.即dynamic x意味着变量x具有类型dynamic.

DynamicObject是一种类型,使其易于实现IDynamicMetaObjectProvider,从而覆盖该类型的特定绑定行为.

ExpandoObject是一种类似于财产袋的类型.即,您可以在运行时向此类型的动态实例添加属性,方法等.

  • `dynamic`不是一个实际的类型......它只是告诉编译器对此变量使用后期绑定的提示.`dynamic`变量实际上在MSIL中声明为`object` (23认同)
  • @Thomas:语言规范说"C#4.0引入了一种名为dynamic的新静态类型". (3认同)
  • @NathanA我和你在一起.但是,语言规范称它为一种类型,所以这就是我要使用的. (3认同)