首页 文章

ExpandoObject的真正好处是什么?

提问于
浏览
533

添加到.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而不是仅仅使用任意字典类型可以获得什么 real 优点,除了在运行时确定将要确定的情况 .

10 回答

  • 636

    自从我写了你所指的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);
       }
    }
    
  • 18

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

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

  • 13

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

    public dynamic SomeData { get; set; }
    

    ...

    SomeData.WhatEver = "Yo Man!";
    

    ...

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

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

  • 26

    这一切都与程序员的便利性有关 . 我可以想象用这个对象编写快速和脏的程序 .

  • 0

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

    那,并且我会想到与动态语言互操作 .

  • 4

    关于使用ExpandoObject为传入的结构化数据(即XML,Json)创建动态ad-hoc类型的例子非常好MSDN article .

    我们还可以将委托分配给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 .

  • 71

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

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

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

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

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

    我认为只有一切都有效,因为所有东西都有一个ToString(),否则你必须知道它的类型并将'对象'转换为该类型 .


    其中一些比其他更有用,我试图彻底 .

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

    • 好像这可以用作一个非常好的元组 . 您仍然可以致电您的会员“Item1”,“Item2”等...但是现在你没有,它也是可变的,不像一个元组 . 这确实存在缺乏智能感知支持的巨大缺点 .

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

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

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

    • 您不能在类中使用dynamic作为数据成员,可能因为它至少有点像关键字,希望您可以使用ExpandoObject .

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


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

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

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

    很遗憾你不能让代码构建其中一些并将结果推送到intellisense . 我不确定这会怎么样 .

    如果他们可以拥有 Value 和成员,那就太好了 .

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

    在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支持

相关问题