ExpandoObject、DynamicObject 和动态之间的区别

发布于 2024-09-16 02:15:05 字数 145 浏览 13 评论 0原文

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

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

What are the differences between System.Dynamic.ExpandoObject, System.Dynamic.DynamicObject and dynamic?

In which situations do you use these types?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

鹿童谣 2024-09-23 02:15:05

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

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

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

ExpandoObjectDynamicObject 类是 IDynamicMetaObjectProvider 的实现。

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

The dynamic keyword is used to declare variables that should be late-bound.
If you want to use late binding, for any real or imagined type, you use the dynamic keyword and the compiler does the rest.

When you use the dynamic keyword to interact with a normal instance, the DLR performs late-bound calls to the instance's normal methods.

The IDynamicMetaObjectProvider interface allows a class to take control of its late-bound behavior.
When you use the dynamic keyword to interact with an IDynamicMetaObjectProvider implementation, the DLR calls the IDynamicMetaObjectProvider methods and the object itself decides what to do.

The ExpandoObject and DynamicObject classes are implementations of IDynamicMetaObjectProvider.

ExpandoObject is a simple class which allows you to add members to an instance and use them dynamically.
DynamicObject is a more advanced implementation which can be inherited to easily provide customized behavior.

深居我梦 2024-09-23 02:15:05

我将尝试为这个问题提供更清晰的答案,以清楚地解释动态、ExpandoObject 和 DynamicObject 之间的区别。

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

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

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

  1. DynamicObject 不能直接构造。
  2. 您必须扩展 DynamicObject,以便它对您作为开发人员有任何用处。
  3. 当您扩展 DynamicObject 时,您现在可以提供自定义行为,了解您希望动态分派如何解析运行时内部存储在底层数据表示中的数据。
  4. ExpandoObject 将基础数据存储在字典等中。如果您实现 DynamicObject,则可以将数据存储在您喜欢的任何位置和方式。 (例如,如何获取和设置调度数据完全取决于您)。

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

示例:假设您希望有一个动态类型,每当尝试对不存在的成员(即尚未在运行时添加)进行 get 操作时,该类型都会返回自定义默认值。默认值会说:“对不起,这个罐子里没有饼干!”。如果您想要一个具有类似行为的动态对象,则需要控制未找到字段时发生的情况。 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,它使您可以简单轻松地实现具有独特动态行为的自己的类型。

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

I will try to provide a clearer answer to this question, to explain clearly what the differences are between dynamic, ExpandoObject and DynamicObject.

Very quickly, dynamic is a keyword. It is not a type per-se. It is a keyword that tells the compiler to ignore static type checking at design-time and instead to use late-binding at run-time. So we're not going to spend much time on dynamic in the rest of this answer.

ExpandoObject and DynamicObject are indeed types. On the SURFACE, they look very similar to each other. Both classes implement IDynamicMetaObjectProvider. However, dig deeper and you'll find they're NOT similar at all.

DynamicObject is a partial implementation of IDynamicMetaObjectProvider purely meant to be a starting point for developers to implement their own custom types supporting dynamic dispatch with custom underlying storage and retrieval behavior to make dynamic dispatch work.

  1. DynamicObject can't be constructed directly.
  2. You MUST extend DynamicObject for it to have any use to you as the developer.
  3. When you extend DynamicObject you are now able to provide CUSTOM behavior regarding how you want dynamic dispatch to resolve to data stored internally in your underlying data representation at run-time.
  4. ExpandoObject stores underlying data in a Dictionary, etc. If you implement DynamicObject, you can store data wherever and however you like. (e.g. how you get and set the data on dispatch is entirely up to you).

In short, use DynamicObject when you want to create your OWN types that can be used with the DLR and work with whatever CUSTOM behaviors you'd like.

Example: Imagine that you'd like to have a dynamic type that returns a custom default whenever a get is attempted on a member that does NOT exist (i.e. has not been added at run time). And that default will say, "I'm sorry, there are no cookies in this jar!". If you want a dynamic object that behaves like this, you'll need to control what happens when a field is not found. ExpandoObject will not let you do this. So you'll need to create your own type with unique dynamic member resolution (dispatch) behavior and use that instead of the ready-built ExpandoObject.

You can create a type as follows: (Note, the below code is just for illustration and may not run. To learn about how to properly use DynamicObject, there are many articles and tutorials elsewhere.)

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

Now, we could use this imaginary class we just created as a dynamic type that has a very custom behavior if the field doesn't exist.

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 is a FULL implementation of IDynamicMetaObjectProvider, where the .NET Framework team has made all of these decisions for you. This is useful if you don't need any custom behavior, and you feel that ExpandoObject works good enough for you (90% of the time, ExpandoObject is good enough). So for example, see the following, and that for ExpandoObject, the designers chose to throw an exception if the dynamic member does not exist.

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) { ... }

So to summarize, ExpandoObject is simply one pre-chosen way to extend DynamicObject with certain dynamic dispatch behaviors that will probably work for you, but may not depending on your particular needs.

Whereas, DyanmicObject is a helper BaseType that makes implementing your own types with unique dynamic behaviors simple and easy.

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

困倦 2024-09-23 02:15:05

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

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

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

According to the C# language specification dynamic is a type declaration. I.e. dynamic x means the variable x has the type dynamic.

DynamicObject is a type that makes it easy to implement IDynamicMetaObjectProvider and thus override specific binding behavior for the type.

ExpandoObject is a type that acts like a property bag. I.e. you can add properties, methods and so forth to dynamic instances of this type at runtime.

不爱素颜 2024-09-23 02:15:05

上面的 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;    
        }    
    }    
}

The above example of DynamicObject does not tell the difference clearly, because it's basically implementing the functionality which is already provided by ExpandoObject.

In the two links mentioned below, it is very clear that with the help of DynamicObject, it is possible to preserve/change the actual type (XElement in the example used in below links) and better control on properties and methods.

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;    
        }    
    }    
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文