¿Cuáles son los verdaderos beneficios de ExpandoObject?
La clase ExpandoObject que se agrega a .NET 4 le permite establecer propiedades arbitrariamente en un objeto en tiempo de ejecución.
¿Hay alguna ventaja en esto sobre el uso de un Dictionary<string, object>
, o incluso un Hashtable ? Hasta donde puedo decir, esto no es más que una tabla hash a la que puedes acceder con una sintaxis un poco más concisa.
Por ejemplo, ¿por qué es esto?
dynamic obj = new ExpandoObject();
obj.MyInt = 3;
obj.MyString = "Foo";
Console.WriteLine(obj.MyString);
Realmente mejor, o sustancialmente diferente, que:
var obj = new Dictionary<string, object>();
obj["MyInt"] = 3;
obj["MyString"] = "Foo";
Console.WriteLine(obj["MyString"]);
¿Qué ventajas reales se obtienen al usar ExpandoObject en lugar de simplemente usar un tipo de diccionario arbitrario, además de no ser obvio que estás usando un tipo que se determinará en tiempo de ejecución?
Dado que escribí el artículo de MSDN al que te refieres, supongo que tengo que responder a esta.
Primero, anticipé esta pregunta y es por eso que escribí una publicación de blog que muestra un caso de uso más o menos real para ExpandoObject: Dinámico en C# 4.0: Introducción a ExpandoObject .
En breve, ExpandoObject puede ayudarle a crear objetos jerárquicos complejos. Por ejemplo, imagina que tienes un diccionario dentro de un diccionario:
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"]);
Cuanto más profunda es la jerarquía, más feo es el código. Con ExpandoObject, sigue siendo elegante y legible.
dynamic expando = new ExpandoObject();
expando.Address = new ExpandoObject();
expando.Address.State = "WA";
Console.WriteLine(expando.Address.State);
En segundo lugar, como ya se señaló, ExpandoObject implementa la interfaz INotifyPropertyChanged que le brinda más control sobre las propiedades que un diccionario.
Finalmente, puedes agregar eventos a ExpandoObject como aquí:
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;
e?.Invoke(d, new EventArgs());
}
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);
}
}
Además, tenga en cuenta que nada le impide aceptar argumentos de eventos de forma dinámica. En otras palabras, en lugar de usar EventHandler
, puedes usar EventHandler<dynamic>
what haría que el segundo argumento del controlador sea dynamic
.
Una ventaja es para escenarios vinculantes. Las cuadrículas de datos y las cuadrículas de propiedades recogerán las propiedades dinámicas a través del sistema TypeDescriptor. Además, el enlace de datos de WPF comprenderá las propiedades dinámicas, por lo que los controles de WPF pueden enlazarse a un ExpandoObject más fácilmente que un diccionario.
En algunos escenarios también puede ser una consideración la interoperabilidad con lenguajes dinámicos, que esperarán propiedades DLR en lugar de entradas de diccionario.