被添加到. net 4中的ExpandoObject类允许您在运行时任意地为对象设置属性。

与使用Dictionary<string, object>,甚至哈希表相比,这有什么优点吗?据我所知,这只是一个哈希表,您可以使用稍微简洁的语法访问它。

举个例子,为什么是这样:

dynamic obj = new ExpandoObject();
obj.MyInt = 3;
obj.MyString = "Foo";
Console.WriteLine(obj.MyString);

比:更好的或有本质区别的:

var obj = new Dictionary<string, object>();
obj["MyInt"] = 3;
obj["MyString"] = "Foo";

Console.WriteLine(obj["MyString"]);

使用ExpandoObject而不是使用任意的字典类型有什么真正的好处,除了不明显地表明您使用的是将在运行时确定的类型。


当前回答

既然你提到的那篇MSDN文章是我写的,我想我必须回答这个问题。

首先,我预料到了这个问题,这就是为什么我写了一篇博客文章,展示了c# 4.0中ExpandoObject: Dynamic的一个或多或少的真实用例:介绍ExpandoObject。

简单地说,ExpandoObject可以帮助您创建复杂的分层对象。例如,假设你在一个字典中有一个字典:

Dictionary<String, object> dict = new Dictionary<string, object>();
Dictionary<String, object> address = new Dictionary<string,object>();
dict["Address"] = address;
address["State"] = "WA";
Console.WriteLine(((Dictionary<string,object>)dict["Address"])["State"]);

层次结构越深,代码就越丑。使用ExpandoObject,它保持优雅和可读。

dynamic expando = new ExpandoObject();
expando.Address = new ExpandoObject();
expando.Address.State = "WA";
Console.WriteLine(expando.Address.State);

第二,正如已经指出的,ExpandoObject实现了INotifyPropertyChanged接口,它比字典更能控制属性。

最后,你可以像这样向ExpandoObject添加事件:

class Program
{
   static void Main(string[] args)
   {
       dynamic d = new ExpandoObject();

       // Initialize the event to null (meaning no handlers)
       d.MyEvent = null;

       // Add some handlers
       d.MyEvent += new EventHandler(OnMyEvent);
       d.MyEvent += new EventHandler(OnMyEvent2);

       // Fire the event
       EventHandler e = d.MyEvent;

       e?.Invoke(d, new EventArgs());
   }

   static void OnMyEvent(object sender, EventArgs e)
   {
       Console.WriteLine("OnMyEvent fired by: {0}", sender);
   }

   static void OnMyEvent2(object sender, EventArgs e)
   {
       Console.WriteLine("OnMyEvent2 fired by: {0}", sender);
   }
}

另外,请记住,没有什么可以阻止您以动态方式接受事件参数。换句话说,您可以使用EventHandler<dynamic>而不是使用EventHandler,这将导致处理程序的第二个参数是动态的。

其他回答

这完全是为了方便程序员。我可以想象用这个对象编写快速而肮脏的程序。

既然你提到的那篇MSDN文章是我写的,我想我必须回答这个问题。

首先,我预料到了这个问题,这就是为什么我写了一篇博客文章,展示了c# 4.0中ExpandoObject: Dynamic的一个或多或少的真实用例:介绍ExpandoObject。

简单地说,ExpandoObject可以帮助您创建复杂的分层对象。例如,假设你在一个字典中有一个字典:

Dictionary<String, object> dict = new Dictionary<string, object>();
Dictionary<String, object> address = new Dictionary<string,object>();
dict["Address"] = address;
address["State"] = "WA";
Console.WriteLine(((Dictionary<string,object>)dict["Address"])["State"]);

层次结构越深,代码就越丑。使用ExpandoObject,它保持优雅和可读。

dynamic expando = new ExpandoObject();
expando.Address = new ExpandoObject();
expando.Address.State = "WA";
Console.WriteLine(expando.Address.State);

第二,正如已经指出的,ExpandoObject实现了INotifyPropertyChanged接口,它比字典更能控制属性。

最后,你可以像这样向ExpandoObject添加事件:

class Program
{
   static void Main(string[] args)
   {
       dynamic d = new ExpandoObject();

       // Initialize the event to null (meaning no handlers)
       d.MyEvent = null;

       // Add some handlers
       d.MyEvent += new EventHandler(OnMyEvent);
       d.MyEvent += new EventHandler(OnMyEvent2);

       // Fire the event
       EventHandler e = d.MyEvent;

       e?.Invoke(d, new EventArgs());
   }

   static void OnMyEvent(object sender, EventArgs e)
   {
       Console.WriteLine("OnMyEvent fired by: {0}", sender);
   }

   static void OnMyEvent2(object sender, EventArgs e)
   {
       Console.WriteLine("OnMyEvent2 fired by: {0}", sender);
   }
}

另外,请记住,没有什么可以阻止您以动态方式接受事件参数。换句话说,您可以使用EventHandler<dynamic>而不是使用EventHandler,这将导致处理程序的第二个参数是动态的。

一个优点是用于绑定场景。数据网格和属性网格将通过TypeDescriptor系统获取动态属性。此外,WPF数据绑定将理解动态属性,因此WPF控件可以比字典更容易地绑定到ExpandoObject。

与动态语言的互操作性(期望使用DLR属性而不是字典条目)在某些场景中也可能需要考虑。

与基于DLR的其他语言进行互操作是我能想到的首要原因。你不能给他们传递Dictionary<string对象>,因为它不是IDynamicMetaObjectProvider。另一个额外的好处是它实现了INotifyPropertyChanged,这意味着在WPF的数据绑定世界中,它还具有Dictionary<K,V>所能提供的额外好处。

这是来自MSDN的一篇很棒的文章,关于使用ExpandoObject为传入的结构化数据(即XML, Json)创建动态特殊类型的示例。

我们还可以将delegate分配给ExpandoObject的动态属性:

dynamic person = new ExpandoObject();
person.FirstName = "Dino";
person.LastName = "Esposito";

person.GetFullName = (Func<String>)(() => { 
  return String.Format("{0}, {1}", 
    person.LastName, person.FirstName); 
});

var name = person.GetFullName();
Console.WriteLine(name);

因此,它允许我们在运行时向动态对象注入一些逻辑。 因此,与lambda表达式、闭包、动态关键字和DynamicObject类一起,我们可以在c#代码中引入一些函数式编程的元素,这些元素是我们从动态语言如JavaScript或PHP中了解到的。