ExpandoObject的真正好处是什么?

时间:2009-10-31 01:09:43

标签: c# .net .net-4.0 c#-4.0

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

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

例如,为什么会这样:

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而不是仅仅使用任意字典类型可以获得什么真正的优势,除了不明显您正在使用将在运行时确定的类型。

10 个答案:

答案 0 :(得分:656)

由于我写了你所指的MSDN文章,我想我必须回答这个问题。

首先,我预料到了这个问题,这就是为什么我写了一篇博文,展示了一个或多或少真实的ExpandoObject用例:Dynamic in C# 4.0: Introducing the 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;

       if (e != null)
       {
           e(d, new EventArgs());
       }

       // We could also fire it with...
       //      d.MyEvent(d, new EventArgs());

       // ...if we knew for sure that the event is non-null.
   }

   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);
   }
}

答案 1 :(得分:74)

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

在某些情况下,可能还需要考虑与动态语言的互操作性,这些语言将期望DLR属性而不是字典条目。

答案 2 :(得分:42)

对我来说真正的好处是来自XAML的完全轻松的数据绑定:

public dynamic SomeData { get; set; }

...

SomeData.WhatEver = "Yo Man!";

...

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

答案 3 :(得分:27)

基于DLR建立的其他语言的互操作是我能想到的第一个原因。您无法将Dictionary<string, object>传递给IDynamicMetaObjectProvider,因为它不是INotifyPropertyChanged。另一个好处是它实现了Dictionary<K,V>,这意味着在WPF的数据绑定世界中,它还具有超出{{1}}可以为您提供的好处。

答案 4 :(得分:19)

这都是程序员的便利。我可以想象用这个对象编写快速而又脏的程序。

答案 5 :(得分:14)

我认为它会有语法上的好处,因为你不再通过使用字典来“伪装”动态添加的属性。

那,我会想到与动态语言互操作。

答案 6 :(得分:11)

来自伟大MSDN article的关于使用 ExpandoObject 为传入的结构化数据(即XML,Json)创建动态ad-hoc类型的示例。

我们还可以将委托分配给 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 class一起,我们可以将函数式编程的一些元素引入到我们的C#代码中,我们从动态语言中知道它们就像JavaScript或PHP。

答案 7 :(得分:4)

在某些情况下,这很方便。例如,我将它用于Modularized shell。每个模块都定义了自己的配置对话框,数据包含在其设置中。我为它提供了一个ExpandoObject作为Datacontext,并将值保存在我的配置存储中。这样,配置对话框编写器只需绑定到一个值,它就会自动创建并保存。 (当然,提供给模块使用这些设置)

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

这就像LINQ只是语法糖,但它有时会让事情变得容易。

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

答案 8 :(得分:-1)

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

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

其中一些比其他人更有用,我正在努力做到彻底。

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

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

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

  4. 您可以为ExpandoObject本身或仅为其成员分配值吗?与动态/动态[]比较和对比,使用最适合您需求的。

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

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

  7. 我希望它“是”一个ExpandoObject,对于标注非常通用的东西可能很有用,代码可以根据使用大量动态内容的类型进行区分。

  8. 如果您可以一次向下钻取多个级别,那就太好了。

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

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

    遗憾的是,你不能让代码构建其中一些并将结果推送到intellisense。我不确定这会如何起作用。

    如果他们可以拥有价值和成员,那就太好了。

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

答案 9 :(得分:-3)

在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));

除了使用元组语法,你还有强类型推理和intlisense支持