web-dev-qa-db-fra.com

Comment puis-je réfléchir sur les membres de l'objet dynamique?

J'ai besoin d'obtenir un dictionnaire des propriétés et de leurs valeurs à partir d'un objet déclaré avec le mot clé dynamic dans .NET 4? Il semble que l'utilisation de la réflexion pour que cela ne fonctionne pas.

Exemple:

dynamic s = new ExpandoObject();
s.Path = "/Home";
s.Name = "Home";

// How do I enumerate the Path and Name properties and get their values?
IDictionary<string, object> propertyValues = ???
122
Flatliner DOA

Si IDynamicMetaObjectProvider peut fournir les noms de membres dynamiques, vous pouvez les obtenir. Voir GetMemberNames implémentation dans la bibliothèque PCL sous licence Apache Dynamitey (qui se trouve dans le nuget), cela fonctionne pour ExpandoObjects et DynamicObjects que implémenter GetDynamicMemberNames et tout autre IDynamicMetaObjectProvider qui fournit un méta-objet avec une implémentation de GetDynamicMemberNames sans test personnalisé au-delà de is IDynamicMetaObjectProvider.

Après avoir obtenu les noms des membres, il est un peu plus difficile d’obtenir la valeur de la bonne façon, mais Impromptu le fait, mais il est plus difficile de pointer uniquement sur les éléments intéressants et d’avoir un sens. Voici documentation et il est égal ou plus rapide que la réflexion, mais il est peu probable qu'il soit plus rapide qu'une recherche dans le dictionnaire pour expando, mais cela fonctionne pour tout objet, expando, dynamique ou original - vous le nommez.

30
jbtule

Dans le cas de ExpandoObject, la classe ExpandoObject implémente réellement IDictionary<string, object> pour ses propriétés, la solution est donc aussi simple que le casting:

IDictionary<string, object> propertyValues = (IDictionary<string, object>)s;

Notez que cela ne fonctionnera pas pour les objets dynamiques généraux. Dans ce cas, vous devrez accéder au DLR via IDynamicMetaObjectProvider.

98
itowlson

Il y a plusieurs scénarios à considérer. Tout d'abord, vous devez vérifier le type de votre objet. Vous pouvez simplement appeler GetType () pour cela. Si le type n'implémente pas IDynamicMetaObjectProvider, vous pouvez utiliser la même réflexion que pour tout autre objet. Quelque chose comme:

var propertyInfo = test.GetType().GetProperties();

Cependant, pour les implémentations IDynamicMetaObjectProvider, la réflexion simple ne fonctionne pas. En gros, vous devez en savoir plus sur cet objet. S'il s'agit de ExpandoObject (qui est l'une des implémentations de IDynamicMetaObjectProvider), vous pouvez utiliser la réponse fournie par itowlson. ExpandoObject stocke ses propriétés dans un dictionnaire et vous pouvez simplement convertir l'objet dynamique en dictionnaire.

S'il s'agit de DynamicObject (une autre implémentation d'IDynamicMetaObjectProvider), vous devez utiliser les méthodes que cet objet DynamicObject expose. DynamicObject n'est pas obligé de "stocker" sa liste de propriétés n'importe où. Par exemple, il pourrait faire quelque chose comme ceci (je réutilise un exemple de mon blog ):

public class SampleObject : DynamicObject
{
    public override bool TryGetMember(GetMemberBinder binder, out object result)
    {
        result = binder.Name;
        return true;
    }
}

Dans ce cas, chaque fois que vous essayez d'accéder à une propriété (avec un nom donné), l'objet renvoie simplement le nom de la propriété sous forme de chaîne.

dynamic obj = new SampleObject();
Console.WriteLine(obj.SampleProperty);
//Prints "SampleProperty".

Donc, vous n'avez rien à considérer - cet objet n'a aucune propriété et, en même temps, tous les noms de propriété valides fonctionneront.

Je dirais que pour les implémentations IDynamicMetaObjectProvider, vous devez filtrer sur les implémentations connues où vous pouvez obtenir une liste de propriétés, telles que ExpandoObject, et ignorer (ou lever une exception) pour le reste.

57
Alexandra Rusina

Nécessite Newtonsoft Json.Net

Un peu tard, mais je suis venu avec cela. Il ne vous donne que les clés et vous pouvez ensuite utiliser celles de la dynamique:

public List<string> GetPropertyKeysForDynamic(dynamic dynamicToGetPropertiesFor)
{
    JObject attributesAsJObject = dynamicToGetPropertiesFor;
    Dictionary<string, object> values = attributesAsJObject.ToObject<Dictionary<string, object>>();
    List<string> toReturn = new List<string>();
    foreach (string key in values.Keys)
    {
        toReturn.Add(key);                
    }
    return toReturn;
}

Ensuite, il vous suffit simplement de faire comme ceci:

foreach(string propertyName in GetPropertyKeysForDynamic(dynamicToGetPropertiesFor))
{
    dynamic/object/string propertyValue = dynamicToGetPropertiesFor[propertyName];
    // And
    dynamicToGetPropertiesFor[propertyName] = "Your Value"; // Or an object value
}

Choisissez d'obtenir la valeur sous forme de chaîne ou d'un autre objet, ou effectuez une autre dynamique et utilisez à nouveau la recherche.

17
Mr. B