182

System.Dynamic.ExpandoObjectSystem.Dynamic.DynamicObject有什么区别dynamic

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

4

4 回答 4

163

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

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

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

ExpandoObjectDynamicObjectIDynamicMetaObjectProvider.

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

于 2010-08-25T11:57:37.620 回答
89

我将尝试为这个问题提供更清晰的答案,以清楚地解释动态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 不会让您这样做。因此,您需要使用独特的动态成员解析(调度)行为创建自己的类型,并使用它而不是现成的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 ,它使实现您自己的具有独特动态行为的类型变得简单易行。

一个有用的教程,上面的大部分示例源都基于该教程。

于 2017-06-21T02:01:45.043 回答
37

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

DynamicObject是一种易于实现IDynamicMetaObjectProvider并因此覆盖该类型的特定绑定行为的类型。

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

于 2010-08-25T11:56:16.340 回答
1

上面的示例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;    
        }    
    }    
}
于 2018-01-25T16:09:07.463 回答