Respuestas:
La dynamicpalabra clave se utiliza para declarar variables que deberían estar vinculadas tarde.
Si desea usar el enlace tardío, para cualquier tipo real o imaginado, use la dynamicpalabra clave y el compilador hace el resto.
Cuando utiliza la dynamicpalabra clave para interactuar con una instancia normal, el DLR realiza llamadas con retraso a los métodos normales de la instancia.
La IDynamicMetaObjectProviderinterfaz permite que una clase tome el control de su comportamiento de enlace tardío.
Cuando utiliza la dynamicpalabra clave para interactuar con una IDynamicMetaObjectProviderimplementación, el DLR llama a los IDynamicMetaObjectProvidermétodos y el propio objeto decide qué hacer.
Las clases ExpandoObjecty DynamicObjectson implementaciones de IDynamicMetaObjectProvider.
ExpandoObjectes una clase simple que le permite agregar miembros a una instancia y usarlos dynamicaliados.
DynamicObjectes 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 ExpandoObjecty DynamicObject.
Muy rápido, dynamices una palabra clave. No es un tipo per-se. Es una palabra clave que le dice al compilador que ignore la verificación de tipo estático en tiempo de diseño y que, en su lugar, use el enlace tardío en tiempo de ejecución. Así que no vamos a pasar mucho tiempo dynamicen el resto de esta respuesta.
ExpandoObjecty de DynamicObjecthecho son tipos. En la SUPERFICIE, se ven muy similares entre sí. Ambas clases implementan IDynamicMetaObjectProvider. Sin embargo, profundice y encontrará que NO son similares en absoluto.
DynamicObject es una implementación parcial que IDynamicMetaObjectProviderpretende ser un punto de partida para que los desarrolladores implementen sus propios tipos personalizados que admiten el despacho dinámico con un comportamiento de recuperación y almacenamiento subyacente personalizado para que el despacho dinámico funcione.
En resumen, use DynamicObject cuando quiera crear sus PROPIOS tipos que puedan usarse con el DLR y trabajar con cualquier comportamiento PERSONALIZADO que desee.
Ejemplo: imagine que le gustaría tener un tipo dinámico que devuelva 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 frasco". Si desea un objeto dinámico que se comporte así, deberá controlar lo que sucede cuando no se encuentra un campo. ExpandoObject no te permitirá hacer esto. Por lo tanto, deberá crear su propio tipo con un comportamiento único de resolución dinámica de miembro (despacho) y usarlo en lugar del listo 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 información sobre cómo usar DynamicObject correctamente, 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!")
ExpandoObjectes 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 (el 90% del tiempo, ExpandoObjectes lo suficientemente bueno). Entonces, por ejemplo, vea lo siguiente, y que 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) { ... }
En resumen, ExpandoObjectes simplemente una forma preseleccionada de extender DynamicObject con ciertos comportamientos de despacho dinámico que probablemente funcionarán para usted , pero que pueden no depender de sus necesidades particulares.
Mientras que, DyanmicObjectes un BaseType auxiliar que hace que implementar 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.
DynamicObject: al anular TryGetMember, si devuelve falso RuntimeBinderException, se lanzará un al intentar acceder a propiedades no existentes. Para que el fragmento realmente funcione, debes regresar true.
De acuerdo con la especificación del lenguaje C # dynamices una declaración de tipo. Es decir dynamic x, la variable xtiene el tipo dynamic.
DynamicObjectes un tipo que facilita su implementación IDynamicMetaObjectProvidery, por lo tanto, anula el comportamiento de enlace específico para el tipo.
ExpandoObjectes 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.
dynamicno es un tipo real ... es solo una pista para decirle al compilador que use el enlace tardío para esta variable. dynamiclas variables se declaran realmente como objecten MSIL
El ejemplo anterior de DynamicObjectno dice la diferencia claramente, 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 preservar / cambiar el tipo real ( XElementen el ejemplo utilizado en los enlaces a continuación) y un mejor control sobre las propiedades y los métodos.
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;
}
}
}