Pergunta

O ExpandoObject classe sendo adicionado ao .NET 4 permite-lhe propriedades arbitrariamente definidos em um objeto em tempo de execução.

Existem quaisquer vantagens para este mais usando um Dictionary<string, object> , ou realmente até mesmo um Hashtable ? Tanto quanto eu posso dizer, isso não é nada, mas uma tabela hash que você pode acessar com sintaxe um pouco mais sucinto.

Por exemplo, por que é isso:

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

Realmente melhor, ou substancialmente diferente, que:

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

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

O real vantagens são obtidas usando ExpandoObject vez de usar apenas um tipo de dicionário arbitrária, além de não ser óbvio que você está usando um tipo que vai ser determinada em tempo de execução.

Foi útil?

Solução

Desde que escrevi o artigo MSDN você está se referindo, eu acho que tenho que responder a este.

Em primeiro lugar, eu esperava esta questão e é por isso que eu escrevi um post de blog que mostra um caso de uso mais ou menos real para ExpandoObject: dinâmica em C # 4.0: Apresentando a ExpandoObject.

Logo, ExpandoObject pode ajudá-lo a criar objetos hierárquicas complexas. Por exemplo, imagine que você tem um dicionário dentro de um dicionário:

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

A mais profunda é a hierarquia, o mais feio é o código. Com ExpandoObject ele permanece elegante e legível.

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

Em segundo lugar, como já foi salientado, implementos ExpandoObject INotifyPropertyChanged interface de que lhe dá mais controle sobre as propriedades do que um dicionário.

Finalmente, você pode adicionar eventos a ExpandoObject como aqui:

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

Outras dicas

Uma vantagem é para cenários de ligação. grades de dados e redes de propriedade vai pegar as propriedades dinâmicas através do sistema de TypeDescriptor. Além disso, os dados WPF ligação compreenderão propriedades dinâmicas, assim controles WPF pode ligar-se a um ExpandoObject mais prontamente do que um dicionário.

A interoperabilidade com linguagens dinâmicas, que serão esperando propriedades DLR em vez de entradas do dicionário, também pode ser uma consideração em alguns cenários.

O benefício real para mim é os dados totalmente sem esforço de ligação de XAML:

public dynamic SomeData { get; set; }

...

SomeData.WhatEver = "Yo Man!";

...

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

Interop com outras linguagens fundadas na DLR é # 1 razão que eu posso pensar. Você não pode passar-lhes uma Dictionary<string, object> como não é um IDynamicMetaObjectProvider. Outra vantagem é que ele implementa INotifyPropertyChanged que significa no mundo da ligação de dados do WPF também tem benefícios adicionais além do que Dictionary<K,V> pode fornecê-lo.

É tudo sobre a conveniência programador. Eu posso imaginar escrevendo programas rápida e suja com esse objeto.

Eu acho que vai ter um benefício sintática, já que você vai deixar de ser "a fingir" propriedades adicionadas dinamicamente usando um dicionário.

Isso, e interoperabilidade com linguagens dinâmicas eu pensaria.

É de exemplo de grande MSDN artigo sobre o uso de ExpandoObject para a criação de tipos ad-hoc dinâmicas para recepção de dados estruturados (ou seja, XML, JSON).

Podemos delegado também atribuir a ExpandoObject 's propriedade dinâmica:

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

Assim que nos permite injetar um pouco de lógica em objeto dinâmico em tempo de execução. Portanto, juntamente com expressões lambda, fechos, palavra-chave dinâmica e DynamicObject classe , podemos introduzir alguns elementos de programação funcional em nosso código C #, que sabe de linguagens dinâmicas como como JavaScript ou PHP.

Há alguns casos onde isso é útil. Vou usá-lo para um shell Modularized por exemplo. Cada módulo define a sua própria configuração de diálogo databinded às configurações. Eu fornecê-lo com um ExpandoObject como é Datacontext e salvar os valores na minha configuração de armazenamento. Desta forma, o escritor de configuração de diálogo só tem que se ligam a um valor e ele é automaticamente criado e salvo. (E fornecido para o módulo para usar essas configurações, é claro)

É simplesmente mais fácil de usar do que um dicionário. Mas todos devem estar cientes de que internamente ele é apenas um dicionário.

É como LINQ açúcar apenas sintática, mas torna as coisas mais fáceis, às vezes.

Assim, para responder sua pergunta diretamente: É mais fácil escrever e mais fácil de ler. Mas tecnicamente ele é essencialmente um Dictionary<string,object> (Você pode até mesmo lançá-lo em um para listar os valores).

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

Eu acho que só funciona porque tudo tem um ToString (), caso contrário, você tem que saber o tipo que era e lançou o 'objeto' para esse tipo.


Alguns destes são úteis mais frequentemente do que os outros, eu estou tentando ser completa.

  1. Pode ser muito mais natural para acessar uma coleção, neste caso, o que é efetivamente um "dicionário", usando a notação de ponto mais direta.

  2. Parece que isso poderia ser usado como um muito bom Tuple. Você ainda pode chamar seus membros "Item1", "Item2" etc ... mas agora você não tem que, também é mutável, ao contrário de um Tuple. Este tem a enorme desvantagem de falta de apoio intellisense.

  3. Você pode ser desconfortável com "nomes de membros como cordas", como é a sensação com o dicionário, você pode sentir que é também como "cordas de execução", e isso pode levar a convenções de nomenclatura sendo codificados, e lidar com o trabalho com morfemas e sílabas quando o código está tentando entender como usar os membros :-P

  4. Você pode atribuir um valor a um si ExpandoObject ou apenas aos seus membros? Comparar e contrastar com a dinâmica / dinâmico [], usar o que melhor se adapte às suas necessidades.

  5. Eu não acho dinâmica / dinâmico [] trabalha em um loop foreach, você tem que usar var, mas possivelmente você pode usar ExpandoObject.

  6. Você não pode usar dinâmico como um membro de dados em uma classe, talvez porque é, pelo menos, como uma espécie de palavra-chave, espero que você pode com ExpandoObject.

  7. espero que ele "é" uma ExpandoObject, pode ser útil para rotular as coisas muito genéricas à parte, com o código que diferencia com base nos tipos onde há um monte de coisas dinâmica que está sendo usado.


Seja bom se você pudesse detalhar vários níveis ao mesmo tempo.

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

Isso não é o melhor exemplo possível, imaginar usos elegantes como apropriado em seus próprios projetos.

É uma pena que você não pode ter acúmulo de código alguns destes e empurrar os resultados para intellisense. Não tenho certeza de como isso funcionaria embora.

Seria bom se eles poderiam ter um valor, bem como membros.

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

Depois de valueTuples, que é o uso de classe ExpandoObject? este código de 6 linhas com ExpandoObject:

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

pode ser escrito em uma linha com tuplas:

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

além com a sintaxe tupla você tem forte inferência tipo e apoio intlisense

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top