Réponses:
Le dynamicmot-clé est utilisé pour déclarer des variables qui doivent être liées tardivement.
Si vous souhaitez utiliser la liaison tardive, pour tout type réel ou imaginaire, vous utilisez ledynamic mot clé et le compilateur s'occupe du reste.
Lorsque vous utilisez le dynamicmot - clé pour interagir avec une instance normale, le DLR effectue des appels à liaison tardive aux méthodes normales de l'instance.
L' IDynamicMetaObjectProviderinterface permet à une classe de prendre le contrôle de son comportement lié tardivement.
Lorsque vous utilisez le dynamicmot clé pour interagir avec une IDynamicMetaObjectProviderimplémentation, le DLR appelle les IDynamicMetaObjectProviderméthodes et l'objet lui-même décide quoi faire.
Les classes ExpandoObjectet DynamicObjectsont des implémentations de IDynamicMetaObjectProvider.
ExpandoObjectest une classe simple qui vous permet d'ajouter des membres à une instance et de les utiliser dynamicalliés.
DynamicObjectest une implémentation plus avancée qui peut être héritée pour fournir facilement un comportement personnalisé.
Je vais essayer de fournir une réponse plus claire à cette question, d'expliquer clairement quelles sont les différences entre dynamique ExpandoObjectet DynamicObject.
Très vite, dynamicc'est un mot-clé. Ce n'est pas un type en soi. C'est un mot-clé qui indique au compilateur d'ignorer la vérification de type statique au moment du design et à la place d'utiliser la liaison tardive au moment de l'exécution. Nous n'allons donc pas passer beaucoup de temps sur dynamicle reste de cette réponse.
ExpandoObjectet DynamicObjectsont en effet des types. Sur la SURFACE, ils se ressemblent beaucoup. Les deux classes implémentent IDynamicMetaObjectProvider. Cependant, creusez plus profondément et vous constaterez qu'ils ne sont PAS du tout similaires.
DynamicObject est une implémentation partielle de IDynamicMetaObjectProviderpurement destinée à être un point de départ pour que les développeurs implémentent leurs propres types personnalisés prenant en charge la répartition dynamique avec un stockage sous-jacent personnalisé et un comportement de récupération pour faire fonctionner la répartition dynamique.
En bref, utilisez DynamicObject lorsque vous souhaitez créer vos propres types qui peuvent être utilisés avec le DLR et travailler avec les comportements CUSTOM que vous souhaitez.
Exemple: imaginez que vous aimeriez avoir un type dynamique qui renvoie une valeur par défaut personnalisée chaque fois qu'un get est tenté sur un membre qui n'existe PAS (c'est-à-dire qui n'a pas été ajouté au moment de l'exécution). Et cette valeur par défaut dira: "Je suis désolé, il n'y a pas de cookies dans ce pot!". Si vous voulez un objet dynamique qui se comporte comme ça, vous devrez contrôler ce qui se passe lorsqu'un champ n'est pas trouvé. ExpandoObject ne vous permettra pas de faire cela. Vous devrez donc créer votre propre type avec un comportement de résolution de membre dynamique unique (répartition) et l'utiliser à la place du tout prêtExpandoObject .
Vous pouvez créer un type comme suit: (Notez que le code ci-dessous est juste à titre d'illustration et ne peut pas s'exécuter. Pour savoir comment utiliser correctement DynamicObject, il existe de nombreux articles et didacticiels ailleurs.)
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;
}
}
Maintenant, nous pourrions utiliser cette classe imaginaire que nous venons de créer comme type dynamique qui a un comportement très personnalisé si le champ n'existe pas.
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!")
ExpandoObjectest une implémentation COMPLÈTE de IDynamicMetaObjectProvider, où l'équipe .NET Framework a pris toutes ces décisions pour vous. Ceci est utile si vous n'avez besoin d'aucun comportement personnalisé et que vous pensez qu'ExpandoObject fonctionne assez bien pour vous (90% du temps, ExpandoObjectc'est assez bien). Ainsi, par exemple, voyez ce qui suit, et que pour ExpandoObject, les concepteurs ont choisi de lever une exception si le membre dynamique n'existe pas.
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) { ... }
Donc, pour résumer, ExpandoObjectest simplement un moyen pré-choisi d'étendre DynamicObject avec certains comportements de répartition dynamique qui fonctionneront probablement pour vous , mais peuvent ne pas dépendre de vos besoins particuliers.
Considérant que, DyanmicObjectest une aide BaseType qui facilite et simplifie l'implémentation de vos propres types avec des comportements dynamiques uniques.
Un didacticiel utile sur lequel une grande partie de l'exemple de source ci-dessus est basé.
DynamicObject: lors de la substitution TryGetMember, si vous retournez false, un RuntimeBinderExceptionsera renvoyé lors de la tentative d'accès à une propriété non existante. Pour que l'extrait fonctionne réellement, vous devez revenir true.
Selon la spécification du langage C #, il dynamicy a une déclaration de type. Ie dynamic xsignifie que la variable xa le type dynamic.
DynamicObjectest un type qui facilite l'implémentation IDynamicMetaObjectProvideret remplace ainsi le comportement de liaison spécifique du type.
ExpandoObjectest un type qui agit comme un sac de propriété. C'est-à-dire que vous pouvez ajouter des propriétés, des méthodes, etc. aux instances dynamiques de ce type lors de l'exécution.
dynamicn'est pas un type réel ... c'est juste un indice pour dire au compilateur d'utiliser une liaison tardive pour cette variable. dynamicles variables sont effectivement déclarées comme objectdans MSIL
L'exemple ci-dessus de DynamicObjectne fait pas clairement la différence, car il implémente essentiellement la fonctionnalité déjà fournie parExpandoObject .
Dans les deux liens mentionnés ci-dessous, il est très clair qu'avec l'aide de DynamicObject, il est possible de conserver / modifier le type réel ( XElementdans l'exemple utilisé dans les liens ci-dessous) et de mieux contrôler les propriétés et les méthodes.
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;
}
}
}