被添加到. 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而不是使用任意的字典类型有什么真正的好处,除了不明显地表明您使用的是将在运行时确定的类型。


当前回答

var obj = new Dictionary<string, object>;
...
Console.WriteLine(obj["MyString"]);

我认为这只会起作用,因为所有东西都有一个ToString(),否则你必须知道它的类型,并将“对象”转换为该类型。


有些方法比其他方法更有用,我尽量讲得透彻些。

It may be far more natural to access a collection, in this case what is effectively a "dictionary", using the more direct dot notation. It seems as if this could be used as a really nice Tuple. You can still call your members "Item1", "Item2" etc... but now you don't have to, it's also mutable, unlike a Tuple. This does have the huge drawback of lack of intellisense support. You may be uncomfortable with "member names as strings", as is the feel with the dictionary, you may feel it is too like "executing strings", and it may lead to naming conventions getting coded in, and dealing with working with morphemes and syllables when code is trying understand how to use members :-P Can you assign a value to an ExpandoObject itself or just it's members? Compare and contrast with dynamic/dynamic[], use whichever best suits your needs. I don't think dynamic/dynamic[] works in a foreach loop, you have to use var, but possibly you can use ExpandoObject. You cannot use dynamic as a data member in a class, perhaps because it's at least sort of like a keyword, hopefully you can with ExpandoObject. I expect it "is" an ExpandoObject, might be useful to label very generic things apart, with code that differentiates based on types where there is lots of dynamic stuff being used.


如果你能一次钻到多个层次就好了。

var e = new ExpandoObject();
e.position.x = 5;
etc...

这不是最好的例子,想象一下在你自己的项目中优雅的使用。

遗憾的是,你不能让代码构建其中的一些,并将结果推送到智能感知。但我不确定这是怎么回事。

如果它们能像成员一样有价值就好了。

var fifteen = new ExpandoObject();
fifteen = 15;
fifteen.tens = 1;
fifteen.units = 5;
fifteen.ToString() = "fifteen";
etc...

其他回答

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

var obj = new Dictionary<string, object>;
...
Console.WriteLine(obj["MyString"]);

我认为这只会起作用,因为所有东西都有一个ToString(),否则你必须知道它的类型,并将“对象”转换为该类型。


有些方法比其他方法更有用,我尽量讲得透彻些。

It may be far more natural to access a collection, in this case what is effectively a "dictionary", using the more direct dot notation. It seems as if this could be used as a really nice Tuple. You can still call your members "Item1", "Item2" etc... but now you don't have to, it's also mutable, unlike a Tuple. This does have the huge drawback of lack of intellisense support. You may be uncomfortable with "member names as strings", as is the feel with the dictionary, you may feel it is too like "executing strings", and it may lead to naming conventions getting coded in, and dealing with working with morphemes and syllables when code is trying understand how to use members :-P Can you assign a value to an ExpandoObject itself or just it's members? Compare and contrast with dynamic/dynamic[], use whichever best suits your needs. I don't think dynamic/dynamic[] works in a foreach loop, you have to use var, but possibly you can use ExpandoObject. You cannot use dynamic as a data member in a class, perhaps because it's at least sort of like a keyword, hopefully you can with ExpandoObject. I expect it "is" an ExpandoObject, might be useful to label very generic things apart, with code that differentiates based on types where there is lots of dynamic stuff being used.


如果你能一次钻到多个层次就好了。

var e = new ExpandoObject();
e.position.x = 5;
etc...

这不是最好的例子,想象一下在你自己的项目中优雅的使用。

遗憾的是,你不能让代码构建其中的一些,并将结果推送到智能感知。但我不确定这是怎么回事。

如果它们能像成员一样有价值就好了。

var fifteen = new ExpandoObject();
fifteen = 15;
fifteen.tens = 1;
fifteen.units = 5;
fifteen.ToString() = "fifteen";
etc...

这是来自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中了解到的。

既然你提到的那篇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属性而不是字典条目)在某些场景中也可能需要考虑。