c# - read - Diferencias entre ExpandoObject, DynamicObject y dynamic
read dynamic object c# (4)
De acuerdo con la especificación del lenguaje C #, la dynamic
es una declaración de tipo. Es decir, dynamic x
significa que la variable x
tiene el tipo dynamic
.
DynamicObject
es un tipo que facilita la implementación de IDynamicMetaObjectProvider
y anula el comportamiento de enlace específico para el tipo.
ExpandoObject
es un tipo que actúa como una bolsa de propiedades. Es decir, puede agregar propiedades, métodos, etc. a instancias dinámicas de este tipo en tiempo de ejecución.
¿Cuáles son las diferencias entre System.Dynamic.ExpandoObject
, System.Dynamic.DynamicObject
y dynamic
?
¿En qué situaciones usa estos tipos?
El ejemplo anterior de DynamicObject
no distingue claramente la diferencia, porque básicamente está implementando la funcionalidad que ya proporciona ExpandoObject
.
En los dos enlaces mencionados a continuación, es muy claro que con la ayuda de DynamicObject
, es posible conservar / cambiar el tipo real ( XElement
en el ejemplo utilizado en los enlaces a continuación) y un mejor control de las propiedades y métodos.
blogs.msdn.microsoft.com/csharpfaq/2009/09/30/…
blogs.msdn.microsoft.com/csharpfaq/2009/10/19/…
public class DynamicXMLNode : DynamicObject
{
XElement node;
public DynamicXMLNode(XElement node)
{
this.node = node;
}
public DynamicXMLNode()
{
}
public DynamicXMLNode(String name)
{
node = new XElement(name);
}
public override bool TrySetMember(
SetMemberBinder binder, object value)
{
XElement setNode = node.Element(binder.Name);
if (setNode != null)
setNode.SetValue(value);
else
{
if (value.GetType() == typeof(DynamicXMLNode))
node.Add(new XElement(binder.Name));
else
node.Add(new XElement(binder.Name, value));
}
return true;
}
public override bool TryGetMember(
GetMemberBinder binder, out object result)
{
XElement getNode = node.Element(binder.Name);
if (getNode != null)
{
result = new DynamicXMLNode(getNode);
return true;
}
else
{
result = null;
return false;
}
}
}
La palabra clave dynamic
se usa para declarar las variables que se deben vincular con retraso.
Si desea utilizar la vinculación tardía, para cualquier tipo real o imaginado, use la palabra clave dynamic
y el compilador hace el resto.
Cuando utiliza la palabra clave dynamic
para interactuar con una instancia normal, el DLR realiza llamadas con destino tardío a los métodos normales de la instancia.
La interfaz IDynamicMetaObjectProvider
permite que una clase controle su comportamiento de límite tardío.
Cuando utiliza la palabra clave dynamic
para interactuar con una implementación IDynamicMetaObjectProvider
, el DLR llama a los métodos IDynamicMetaObjectProvider
y el objeto en sí decide qué hacer.
Las clases ExpandoObject
y DynamicObject
son implementaciones de IDynamicMetaObjectProvider
.
ExpandoObject
es una clase simple que le permite agregar miembros a una instancia y usarlos como aliados dynamic
.
DynamicObject
es una implementación más avanzada que se puede heredar para proporcionar fácilmente un comportamiento personalizado.
Trataré de proporcionar una respuesta más clara a esta pregunta, para explicar claramente cuáles son las diferencias entre dinámico, ExpandoObject
y DynamicObject
.
Muy rápido, dynamic
es una palabra clave. No es un tipo per se. Es una palabra clave que le dice al compilador que ignore la comprobación del tipo estático en tiempo de diseño y en su lugar utilice el enlace tardío en el tiempo de ejecución. Así que no vamos a dedicar mucho tiempo a la dynamic
en el resto de esta respuesta.
ExpandoObject
y DynamicObject
son de hecho tipos. En la SUPERFICIE, se ven muy similares entre sí. Ambas clases implementan IDynamicMetaObjectProvider
. Sin embargo, ahonda más y verás que NO son similares en absoluto.
DynamicObject es una implementación parcial de IDynamicMetaObjectProvider
pretende ser un punto de partida para que los desarrolladores implementen sus propios tipos personalizados que admiten el despacho dinámico con un comportamiento de almacenamiento y recuperación subyacente personalizado para hacer que el despacho dinámico funcione.
- DynamicObject no se puede construir directamente.
- DEBE extender DynamicObject para que pueda usarlo como desarrollador.
- Cuando extiende DynamicObject, ahora puede proporcionar un comportamiento CUSTOM con respecto a cómo desea que el despacho dinámico se resuelva en datos almacenados internamente en su representación de datos subyacente en tiempo de ejecución.
- ExpandoObject almacena datos subyacentes en un diccionario, etc. Si implementa DynamicObject, puede almacenar datos donde y como desee. (por ejemplo, cómo obtienes y configuras los datos en el envío depende totalmente de ti).
En resumen, use DynamicObject cuando desee crear sus propios tipos que se puedan usar con el DLR y trabaje con los comportamientos CUSTOM que desee.
Ejemplo: Imagine que desea tener un tipo dinámico que devuelve un valor predeterminado personalizado cada vez que se intenta obtener un miembro que NO existe (es decir, no se ha agregado en tiempo de ejecución). Y ese valor predeterminado dirá: "Lo siento, no hay cookies en este contenedor". Si desea un objeto dinámico que se comporte así, tendrá que controlar lo que sucede cuando no se encuentra un campo. ExpandoObject no te dejará hacer esto. Por lo tanto, deberá crear su propio tipo con un comportamiento único de resolución dinámica de miembros (despacho) y usarlo en lugar del ExpandoObject
.
Puede crear un tipo de la siguiente manera: (Tenga en cuenta que el siguiente código es solo para ilustración y puede que no se ejecute. Para obtener más información acerca de cómo usar adecuadamente DynamicObject, hay muchos artículos y tutoriales en otros lugares).
public class MyNoCookiesInTheJarDynamicObject : DynamicObject
{
Dictionary<string, object> properties = new Dictionary<string, object>();
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
if (properties.ContainsKey(binder.Name))
{
result = properties[binder.Name];
return true;
}
else
{
result = "I''m sorry, there are no cookies in this jar!"; //<-- THIS IS OUR
CUSTOM "NO COOKIES IN THE JAR" RESPONSE FROM OUR DYNAMIC TYPE WHEN AN UNKNOWN FIELD IS ACCESSED
return false;
}
}
public override bool TrySetMember(SetMemberBinder binder, object value)
{
properties[binder.Name] = value;
return true;
}
public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result)
{
dynamic method = properties[binder.Name];
result = method(args[0].ToString(), args[1].ToString());
return true;
}
}
Ahora, podríamos usar esta clase imaginaria que acabamos de crear como un tipo dinámico que tiene un comportamiento muy personalizado si el campo no existe.
dynamic d = new MyNoCookiesInTheJarDynamicObject();
var s = d.FieldThatDoesntExist;
//in our contrived example, the below should evaluate to true
Assert.IsTrue(s == "I''m sorry, there are no cookies in this jar!")
ExpandoObject
es una implementación COMPLETA de IDynamicMetaObjectProvider
, donde el equipo de .NET Framework ha tomado todas estas decisiones por usted. Esto es útil si no necesita ningún comportamiento personalizado, y siente que ExpandoObject funciona lo suficientemente bien para usted (90% de las veces, ExpandoObject
es lo suficientemente bueno). Por ejemplo, consulte lo siguiente, y para ExpandoObject, los diseñadores optaron por lanzar una excepción si el miembro dinámico no existe.
dynamic d = new ExpandoObject();
/*
The ExpandoObject designers chose that this operation should result in an
Exception. They did not have to make that choice, null could
have been returned, for example; or the designers could''ve returned a "sorry no cookies in the jar" response like in our custom class. However, if you choose to use
ExpandoObject, you have chosen to go with their particular implementation
of DynamicObject behavior.
*/
try {
var s = d.FieldThatDoesntExist;
}
catch(RuntimeBinderException) { ... }
Por lo tanto, para resumir, ExpandoObject
es simplemente una forma pre-elegida para extender DynamicObject con ciertos comportamientos de despacho dinámico que probablemente funcionen para usted , pero puede no depender de sus necesidades particulares.
Considerando que, DyanmicObject
es un BaseType auxiliar que hace que la implementación de sus propios tipos con comportamientos dinámicos únicos sea simple y fácil.
Un tutorial útil en el que se basa gran parte de la fuente de ejemplo anterior.