Domanda

La ExpandoObject l'aggiunta a .NET 4 consente di impostare arbitrariamente le proprietà su un oggetto in fase di esecuzione.

Ci sono dei vantaggi rispetto all'utilizzo di un Dictionary<string, object> o addirittura un Hashtable ? Per quanto posso dire, questo non è altro che una tabella hash a cui puoi accedere con una sintassi leggermente più concisa.

Ad esempio, perché è questo:

dynamic obj = new ExpandoObject();
obj.MyInt = 3;
obj.MyString = "Foo";
Console.WriteLine(obj.MyString);

Davvero migliore o sostanzialmente diverso da:

var obj = new Dictionary<string, object>();
obj["MyInt"] = 3;
obj["MyString"] = "Foo";

Console.WriteLine(obj["MyString"]);

Quali vantaggi reali si ottengono usando ExpandoObject invece di usare solo un tipo di dizionario arbitrario, oltre a non essere ovvio che si sta utilizzando un tipo che verrà determinato in fase di esecuzione.

È stato utile?

Soluzione

Da quando ho scritto l'articolo MSDN a cui ti riferisci, immagino di dover rispondere a questo.

Innanzitutto, ho anticipato questa domanda ed è per questo che ho scritto un post sul blog che mostra un caso d'uso più o meno reale per ExpandoObject: Dinamica in C # 4.0: Presentazione di ExpandoObject .

In breve, ExpandoObject può aiutarti a creare oggetti gerarchici complessi. Ad esempio, immagina di avere un dizionario all'interno di un dizionario:

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"]);

Più profonda è la gerarchia, più brutto è il codice. Con ExpandoObject rimane elegante e leggibile.

dynamic expando = new ExpandoObject();
expando.Address = new ExpandoObject();
expando.Address.State = "WA";
Console.WriteLine(expando.Address.State);

In secondo luogo, come è stato già sottolineato, ExpandoObject implementa l'interfaccia INotifyPropertyChanged che offre un maggiore controllo sulle proprietà rispetto a un dizionario.

Infine, puoi aggiungere eventi a ExpandoObject come qui:

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

Altri suggerimenti

Un vantaggio è rappresentato dagli scenari vincolanti. Le griglie dati e le griglie delle proprietà acquisiranno le proprietà dinamiche tramite il sistema TypeDescriptor. Inoltre, l'associazione dei dati WPF comprenderà le proprietà dinamiche, quindi i controlli WPF possono associarsi a un ExpandoObject più facilmente di un dizionario.

L'interoperabilità con i linguaggi dinamici, che si aspetteranno le proprietà DLR anziché le voci del dizionario, può anche essere considerata in alcuni scenari.

Il vero vantaggio per me è l'associazione di dati totalmente semplice da XAML:

public dynamic SomeData { get; set; }

...

SomeData.WhatEver = "Yo Man!";

...

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

L'interoperabilità con altre lingue basate sul DLR è la ragione principale per cui mi viene in mente. Non puoi passare loro un Dictionary<string, object> in quanto non è un IDynamicMetaObjectProvider. Un altro vantaggio aggiunto è che implementa INotifyPropertyChanged il che significa che nel mondo del database di WPF ha anche aggiunto vantaggi oltre a ciò che Dictionary<K,V> può fornirti.

Riguarda la comodità del programmatore. Posso immaginare di scrivere programmi veloci e sporchi con questo oggetto.

Penso che avrà un vantaggio sintattico, dal momento che non sarai più " fingendo " proprietà aggiunte dinamicamente usando un dizionario.

Quello, e interagire con linguaggi dinamici, penso.

È un esempio del fantastico articolo MSDN sull'uso di ExpandoObject per la creazione di tipi dinamici ad hoc per dati strutturati in entrata (ad es. XML, Json).

Possiamo anche assegnare un delegato alla proprietà dinamica di 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);

Quindi ci permette di iniettare un po 'di logica nell'oggetto dinamico in fase di runtime. Pertanto, insieme a espressioni lambda, chiusure, parole chiave dinamiche e Classe DynamicObject , possiamo introdurre alcuni elementi di programmazione funzionale nel nostro codice C #, che conosciamo da linguaggi dinamici come JavaScript o PHP.

Ci sono alcuni casi in cui questo è utile. Lo userò ad esempio per una shell modulare. Ogni modulo definisce la propria finestra di configurazione associata alle proprie impostazioni. Fornisco un ExpandoObject in quanto Datacontext e salvo i valori nella mia memoria di configurazione. In questo modo il writer della finestra di dialogo di configurazione deve solo associarsi a un valore e viene automaticamente creato e salvato. (E fornito al modulo per l'utilizzo di queste impostazioni ovviamente)

E 'semplicemente più facile da usare di un dizionario. Ma tutti dovrebbero essere consapevoli che internamente è solo un dizionario.

È come LINQ solo zucchero sintattico, ma a volte rende le cose più facili.

Quindi, per rispondere direttamente alla tua domanda: è più facile da scrivere e più facile da leggere. Ma tecnicamente si tratta essenzialmente di un Dictionary<string,object> (puoi persino lanciarlo in uno per elencare i valori).

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

Penso che funzioni solo perché tutto ha un ToString (), altrimenti dovresti conoscere il tipo che era e lanciare "l'oggetto" su quel tipo.


Alcuni di questi sono utili più spesso di altri, sto cercando di essere accurato.

  1. Potrebbe essere molto più naturale accedere a una raccolta, in questo caso ciò che è effettivamente un " dizionario " ;, usando la notazione punto più diretta.

  2. Sembra che questo possa essere usato come una Tupla davvero carina. Puoi ancora chiamare i tuoi membri & Quot; Item1 & Quot ;, & Quot; Item2 & Quot; ecc ... ma ora non è necessario, è anche mutabile, a differenza di una Tupla. Questo ha l'enorme inconveniente della mancanza di supporto intellisense.

  3. Potresti sentirti a disagio con " nomi dei membri come stringhe " ;, come è la sensazione con il dizionario, potresti pensare che sia troppo simile a " esecuzione delle stringhe quot; e può portare alla codifica delle convenzioni di denominazione e alla gestione del lavoro con morfemi e sillabe quando il codice cerca di capire come usare i membri :-P

  4. Puoi assegnare un valore a un ExpandoObject stesso o solo ai suoi membri? Confronta e contrapponi a dinamico / dinamico [], usa quello che più si adatta alle tue esigenze.

  5. Non credo che dinamico / dinamico [] funzioni in un ciclo foreach, devi usare var, ma probabilmente puoi usare ExpandoObject.

  6. Non puoi usare la dinamica come membro di dati in una classe, forse perché è almeno un po 'come una parola chiave, speriamo che tu possa farlo con ExpandoObject.

  7. Lo aspetto " è " un ExpandoObject, potrebbe essere utile per etichettare le cose molto generiche, con il codice che si differenzia in base ai tipi in cui sono utilizzate molte cose dinamiche.


Sii gentile se puoi analizzare più livelli contemporaneamente.

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

Non è il miglior esempio possibile, immagina usi eleganti appropriati nei tuoi progetti.

È un peccato che non si possa avere il codice per costruirne alcuni e spingere i risultati su intellisense. Non sono sicuro di come funzioni.

Sii gentile se possono avere un valore oltre ai membri.

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

Dopo valueTuples, a che serve la classe ExpandoObject? questo codice a 6 righe con ExpandoObject:

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

può essere scritto in una riga con le tuple:

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

inoltre con la sintassi tupla hai una forte inferenza di tipo e supporto intlisense

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top