ExpandoObject的真正好处是什么?

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

151143 次浏览

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

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

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

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

我认为这将在语法上有好处,因为您将不再使用字典来“伪造”动态添加的属性。

我认为,还有与动态语言的互操作。

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

首先,我预料到了这个问题,这就是为什么我写了一篇博客文章,展示了ExpandoObject的一个或多或少的真实用例:c# 4.0中的动态:介绍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,这将导致处理程序的第二个参数为dynamic

对我来说,真正的好处是完全不费力的XAML数据绑定:

public dynamic SomeData { get; set; }

...

SomeData.WhatEver = "Yo Man!";

...

 <TextBlock Text="{Binding SomeData.WhatEver}" />

在某些情况下,这很方便。例如,我将把它用于模块化shell。每个模块都定义了自己的配置对话框,该对话框与它的设置绑定。我为它提供了一个ExpandoObject,因为它是Datacontext,并将值保存在我的配置存储。这样,配置对话框编写者只需要绑定到一个值,它就会自动创建和保存。(当然,提供给模块用于使用这些设置)

它只是比字典更容易使用。但每个人都应该意识到,在内部它只是一本词典。

就像LINQ只是语法糖一样,但有时它让事情变得更简单。

所以直接回答你的问题:它更容易写,也更容易读。但从技术上讲,它本质上是一个Dictionary<string,object>(您甚至可以将其转换为一个以列出值)。

这是一个来自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中了解到的
var obj = new Dictionary<string, object>;
...
Console.WriteLine(obj["MyString"]);

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


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

  1. 使用更直接的点表示法访问一个集合,在这种情况下,它实际上是一个“字典”,可能会更自然。

  2. 这似乎可以用作一个非常好的元组。你仍然可以称你的成员为“Item1”,“Item2”等等…但现在你不必这么做了,它也是可变的,不像元组。这确实有缺乏智能感知支持的巨大缺点。

  3. 你可能对“成员名作为字符串”感到不舒服,就像对字典的感觉一样,你可能觉得它太像“执行字符串”了,它可能会导致命名约定被编码,并在代码试图理解如何使用成员时处理语素和音节:-P

  4. 你能给一个ExpandoObject本身或者只是它的成员赋值吗?比较和对比dynamic/dynamic[],使用最适合您的需求。

  5. 我不认为dynamic/dynamic[]在foreach循环中起作用,你必须使用var,但可能你可以使用ExpandoObject。

  6. 你不能在类中使用dynamic作为数据成员,也许是因为它至少有点像关键字,希望你可以用ExpandoObject。

  7. 我希望它“是”一个ExpandoObject,可能有用的标签非常一般的东西分开,与代码区分基于类型,其中有很多动态的东西正在使用。


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

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...
在valueTuples之后,ExpandoObject类有什么用? 这6行代码与ExpandoObject:

dynamic T = new ExpandoObject();
T.x = 1;
T.y = 2;
T.z = new ExpandoObject();
T.z.a = 3;
T.b= 4;

可以用元组写在一行中:

var T = (x: 1, y: 2, z: (a: 3, b: 4));

此外,有了元组语法,你就有了强大的类型推断和inlisense支持