【问题标题】:ExpandoObject - why a Type behaves differently?ExpandoObject - 为什么类型的行为不同?
【发布时间】:2017-08-31 06:27:11
【问题描述】:

一位大师,请说服我/我们这是怎么回事。

   List<ExpandoObject> peopleList = new List<ExpandoObject>();

    dynamic expandoObj1 = new ExpandoObject();
    expandoObj1.id = 1;
    expandoObj1.first = "fred";
    expandoObj1.last = "krugger";
    peopleList.Add(expandoObj1);

    dynamic expandoObj2 = new ExpandoObject();
    expandoObj2.id = 2;
    expandoObj2.first = "george";
    expandoObj2.last = "benson";
    peopleList.Add(expandoObj2);

    //test access the props
    var expObj = expandoObj1; 
    var name = expObj.first;

    var expObj2 = peopleList[0] as dynamic;
    var name2 = expObj2.first; 

    IDictionary<string, object> expObj3 = peopleList[0] as ExpandoObject;
    var name3 = expObj3["first"];

    var expObj4 = peopleList[0] as ExpandoObject;
    //var name4 = expObj4.first; //THIS DOESN'T WORK - ExpandoObject does not contain a definition for 'first' etc...

在所有情况下,左侧都是 System.Dynamic.ExpandoObject; 那么,为什么在第 4 种情况下 expObj4,我无法访问属性 expObj4.first ?

【问题讨论】:

  • 因为变量没有声明为dynamic,这是一个重要的部分!

标签: c#-4.0 dynamic expandoobject


【解决方案1】:

ExpandoObject 是一个将数据存储在字典中的密封类。它实现了 IDynamicMetaObjectProvider 接口,该接口为实现它的类提供动态行为。它还实现了 IDictionary 接口,该接口为其提供了类似字典的行为。它应该在编译时进行检查和验证。

dynamic 是编译器在编译时不应该检查的类型。它在运行时被检查并中断。在编译时,假定动态实体支持任何操作。因此,当您说它是一个扩展对象时,首先调用的字段不会附加到对象本身。

在这里查看expando对象的源代码

https://github.com/Microsoft/referencesource/blob/master/System.Core/Microsoft/Scripting/Actions/ExpandoObject.cs

将动态行为想象成一个对象。你可以把任何类型放在那里。当您添加到列表时,您将添加到列表作为动态,但要添加的项目的固有类型是 ExpandoObject。因此,您可以将其转换回 ExpandoObject。

当你说,

expandoObj1.first = "fred";

意思是一样的

expandoObj1.Add("first", "fred");

你使用的时候

    var expObj = expandoObj1;
    var name = expObj.first;

您使用的是动态形式的 expandoObject。因此,您可以直接访问属性。当您将其转换为 ExpandoObject 类时,您使用的是在 Dictionary 中存储字段的实际 ExpandoObject 类,因此点 (.) 表示法不起作用。

var expObj4 = peopleList[0] as ExpandoObject;

左侧的变量仍然是 ExpandoObject,而不是字典。 ExpandoObject 通过集合搜索公开其成员。

  var name4 = expObj4.Where(t=>t.Key == "first").First().Value;

当你把它转换成字典时,它就像字典一样工作。

IDictionary<string, object> expObj3 = peopleList[0] as ExpandoObject;
  var name3 = expObj3["first"];

当您将其转换为动态时,您可以访问这些键,就像它们是类的属性一样。

进一步参考 Dynamically adding properties to an ExpandoObject

【讨论】:

  • 很好的解释,我只能接受1个答案,所以赞成。
【解决方案2】:

这是因为变量expObj4 被声明为ExpandoObject 而不是dynamic。这是一个重要的区别。

试试这个:

dynamic a = new ExpandoObject();
a.Name = "Test";

这会编译,但以下不会:

ExpandoObject a = new ExpandoObject();
a.Name = "Test";

你明白了:

CS1061“ExpandoObject”不包含“Name”的定义,并且找不到接受“ExpandoObject”类型的第一个参数的扩展方法“Name”

与此相关的变量是:

  • expandoObj1 - 动态
  • expandoObj2 - 动态
  • expObj1 - 动态
  • expObj2 - 动态
  • expObj3 - 字典,但您在这里使用字典访问,而不是点访问

只有当表达式或变量是dynamic 时,编译器的神奇“让我们看看我们是否可以在运行时访问这个东西”代码才会启动。 ExpandoObject 只是一个支持 this的类型。

【讨论】:

    猜你喜欢
    • 2014-02-01
    • 2015-01-02
    • 2016-07-26
    • 1970-01-01
    • 1970-01-01
    • 2018-01-29
    • 1970-01-01
    • 1970-01-01
    • 2012-05-01
    相关资源
    最近更新 更多