2009-10-31 78 views
493

將被添加到.NET 4的ExpandoObject類允許您在運行時任意設置屬性到對象上。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而不是隻使用一個任意上漲字典類型,而不是顯而易見的,你使用的類型將在運行時確定。

回答

589

由於我寫了你指的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); 
    } 
} 
+42

有趣。感謝您的信息:事件。對我來說這是一個新的。 – 2009-11-02 19:11:18

+4

@ Reed 是的,事件尚未記錄在ExpandoObject中。這個特殊的例子實際上出現在博客的討論中。我可能稍後將它添加到文檔中。 – 2009-11-02 19:16:53

+11

@AlexandraRusina,當你說'd.MyEvent = null;'時,它是如何知道這是一個事件?或者它不? – Shimmy 2012-02-06 22:49:32

17

這都是關於程序員的便利。我可以想象用這個對象編寫快速和骯髒的程序。

+8

@J。亨德里克斯,別忘了他還說「髒」。 Intellisense有其不利之處,但是,它使調試和錯誤捕捉更容易。我個人更喜歡靜態的動態類型,除非我處理一個奇怪的(並且總是罕見的)情況。 – Phil 2011-03-10 21:43:38

+0

+1爲方便起見。然而,我發現匿名類型可以像簡單的物業包一樣方便,並且對靜態性更好。 – nawfal 2013-10-21 10:49:05

+0

我不想在生產代碼中使用它,但它在測試代碼中非常方便,並且可以使它看起來非常漂亮。 – Tobias 2014-02-03 18:21:16

64

一個優點是綁定方案。數據網格和屬性網格將通過TypeDescriptor系統獲取動態屬性。另外,WPF數據綁定將理解動態屬性,因此WPF控件可以比字典更容易綁定到ExpandoObject。

在某些情況下,動態語言的互操作性可能也是一個考慮因素,而動態語言會期待DLR屬性而不是字典條目。

+14

+1數據綁定和互操作 – 2010-04-13 07:52:54

+5

它似乎[數據綁定到動態對象被破壞](https://connect.microsoft.com/VisualStudio/feedback/details/522119/databinding-to-dynamic-objects-is-broken)。報告用戶eisenbergeffect來自於caliburn.micro的SO和協調員。 @AlexandraRusina你可以評論bug的狀態和狀態「不會修復」 – surfmuggle 2013-03-05 21:04:02

+0

對於那些好奇的人,我目前能夠綁定到'List '和'IEnumerable '使用WPF4 – 2015-12-04 08:17:21

24

DLR上建立的其他語言互操作是我能想到的第一個理由。你不能通過他們Dictionary<string, object>,因爲它不是IDynamicMetaObjectProvider。另一個額外的好處是它實現了INotifyPropertyChanged,這意味着在WPF的數據綁定世界中,它還具有超越Dictionary<K,V>可以爲您提供的好處。

12

我認爲它會帶來語法上的好處,因爲您不再使用字典「僞裝」動態添加的屬性。

這和我想的動態語言互操作。

31

對我來說,真正受益的是完全不費力的數據從XAML綁定:

public dynamic SomeData { get; set; } 

...

SomeData.WhatEver = "Yo Man!"; 

...

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

在某些情況下,這很方便。例如,我將使用它作爲Modularized外殼。每個模塊定義了它自己的配置對話框數據綁定到它的設置。我爲它提供了一個ExpandoObject,因爲它是Datacontext並將這些值保存在我的配置存儲中。這樣配置對話框編寫器只需綁定一個值並自動創建並保存。 (並提供給模塊使用這些設置當然)

它只是比字典更容易使用。但是每個人都應該知道,內部它只是一個字典。

這就像LINQ只是語法糖,但它有時使事情更容易。

所以直接回答你的問題:它更容易編寫,更易於閱讀。但從技術上講,它本質上是一個Dictionary<string,object>(你甚至可以將它投入到一個列出值)。

8

這是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一樣瞭解這些代碼。

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

我認爲只有工作,因爲任何事物都有一個ToString(),否則你必須知道,這是和投的「對象」到該類型的類型。


其中一些比其他更有用,我試圖徹底。

  1. 訪問一個集合,在這種情況下,實際上是一個「字典」,使用更直接的點符號可能更自然。

  2. 看起來好像這可以作爲一個非常好的元組。你仍然可以打電話給你的成員「Item1」,「Item2」等......但是現在你不需要,它也是可變的,不像Tuple。這確實具有缺乏智能感知支持的巨大缺點。

  3. 您可能會對「成員名稱作爲字符串」感到不舒服,就像字典的感覺一樣,您可能會覺得它太像「正在執行字符串」,並且可能會導致命名約定被編入,並且處理當代碼嘗試瞭解如何使用成員時,與語素和音節一起工作:-P

  4. 您可以爲ExpandoObject本身賦值還是隻賦值給它?與動態/動態[]進行比較和對比,使用最適合您的需求。

  5. 我不認爲動態/動態[]工作在foreach循環,你必須使用var,但可能你可以使用ExpandoObject。

  6. 您不能在類中使用動態數據成員,可能是因爲它至少有點像關鍵字,希望您可以使用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... 
-1

after valueTuples,ExpandoObject類有什麼用? 與ExpandoObject這6行代碼:

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

+0

你的例子在數值元組的意義上是不相同的,你不能寫T.c = 5;在完成定義T之後。使用ExpandoObject,您可以做到這一點,因爲它是動態的。 您使用值元組的示例與聲明匿名類型非常相似。例如:var T2 = new {x = 1,y = 2,z = new {a = 3,b = 4}}; – LxL 2018-02-08 00:15:09

+0

爲什麼我需要編寫T.c = 5而不定義它?在處理不是以.net定義的COM對象時,ExpandoObject只是有用的。否則,我不會使用這個ExpandoObject,因爲它在設計時和運行時都很髒並且很麻煩。 – 2018-02-09 02:55:17

+0

你最初如何將z分配給(a:3,b:4),然後你希望z有額外的c屬性?你可以用值元組來做到嗎? – LxL 2018-02-09 08:11:41