ExpandoObject,DynamicObject和dynamic之间的差异

时间:2010-08-25 11:51:22

标签: c# .net dynamic expandoobject dynamicobject

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

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

4 个答案:

答案 0 :(得分:136)

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

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

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

ExpandoObjectDynamicObject类是IDynamicMetaObjectProvider的实现。

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

答案 1 :(得分:47)

我将尝试为此问题提供更清晰的答案,以清楚地解释动态ExpandoObjectDynamicObject之间的差异。

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

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

DynamicObject是IDynamicMetaObjectProvider的部分实现,纯粹是开发人员实现自己的自定义类型的起点,支持使用自定义底层存储和检索行为进行动态调度,以使动态调度工作。

  1. 无法直接构建DynamicObject。
  2. 您必须扩展DynamicObject,以便它作为开发人员对您有用。
  3. 当您扩展DynamicObject时,您现在能够提供有关如何在运行时将动态分派解析为内部存储在基础数据表示中的数据的CUSTOM行为。
  4. ExpandoObject将基础数据存储在Dictionary等中。如果实现DynamicObject,则可以随时随地存储数据。 (例如,如何获得和设置调度数据完全取决于你)。
  5. 简而言之,当您想要创建可与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!")
    

    ExpandoObjectIDynamicMetaObjectProvider的完整实现,其中.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 ,但可能不会取决于您的特定需求。

    然而, DyanmicObject是一个帮助程序BaseType,它可以简单易用地实现您自己的类型,具有独特的动态行为。

    A useful tutorial on which much of the example source above is based.

答案 2 :(得分:34)

根据C#语言规范dynamic是一个类型声明。即dynamic x表示变量x的类型为dynamic

DynamicObject是一种类型,可以轻松实现IDynamicMetaObjectProvider,从而覆盖该类型的特定绑定行为。

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

答案 3 :(得分:0)

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;    
        }    
    }    
}