ExpandoObject - 为什么Type的行为不同?

时间:2017-08-31 06:27:11

标签: c#-4.0 dynamic expandoobject

对于大师来说,请说服我/我们发生了什么。

   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...

在所有情况下,LEFT-HAND SIDE是System.Dynamic.ExpandoObject; 那么为什么在第四种情况下expObj4,我无法访问属性expObj4.first?

2 个答案:

答案 0 :(得分:2)

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

dynamic是一种在编译时不应由编译器检查的类型。它在运行时被检查并中断。在编译时,假定动态实体支持任何操作。所以,当你说它是一个expandoobject时,名为first的字段不会被附加到对象本身。

在这里查看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类时,您使用的是实际的ExpandoObject类,它将字段存储在Dictionary中,因此点(。)表示法不起作用。

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 :(得分:0)

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

试试这个:

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

这是编译,但以下不是:

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

你明白了:

  

CS1061'ExploreoObject'不包含'Name'的定义,并且没有扩展方法'Name'可以找到接受类型'ExpandoObject'的第一个参数

您拥有的与此相关的变量是:

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

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