84 votes

Convertir Dictionary<string, object> en objet anonyme ?

Tout d'abord, pour plus de clarté, je vais expliquer mon scénario du début :

J'ai une méthode qui a la signature suivante :

public virtual void SendEmail(String from, List recepients, Object model)

Ce que je veux faire, c'est générer un objet anonyme qui a les propriétés de l'objet modèle ainsi que les deux premiers paramètres. Aplatir l'objet modèle en un PropertyInfo[] est très simple. En conséquence, j'ai pensé à créer un dictionnaire qui contiendrait les PropertyInfo et les deux premiers paramètres, puis à les convertir en objet anonyme où la clé est le nom de la propriété et la valeur est la valeur réelle de la propriété.

Est-ce possible ? D'autres suggestions ?

0 votes

Quelle est la raison pour laquelle vous voulez faire cela?

1 votes

Je doute que vous puissiez facilement prendre en charge un ensemble arbitraire de paires clé-valeur - vous devriez construire dynamiquement un nouveau type avec ces propriétés au moment de l'exécution. Étant donné que vous allez ensuite les lire, il serait préférable de créer une surcharge qui accepte également votre dictionnaire.

0 votes

@Rup: En fait, c'est aussi une alternative raisonnable. J'ai déjà trouvé un raccourci qui fonctionne bien pour mes besoins, mais j'aimerais quand même connaître la réponse à ma question ci-dessus... juste par curiosité :)

123voto

svick Points 81772

Si vous voulez vraiment convertir le dictionnaire en un objet qui a les éléments du dictionnaire en tant que propriétés, vous pouvez utiliser ExpandoObject:

var dict = new Dictionary { { "Property", "foo" } };
var eo = new ExpandoObject();
var eoColl = (ICollection>)eo;

foreach (var kvp in dict)
{
    eoColl.Add(kvp);
}

dynamic eoDynamic = eo;

string value = eoDynamic.Property;

2 votes

+1 Mais je ne suis pas sûr comment cela va vous aider.

0 votes

Comment faire la même chose en vb.net?

3 votes

Sur la question de pourquoi vous feriez jamais cela. Lorsque vous passez un modèle à un template Razor, il est plus facile de travailler avec un objet dynamique qu'avec un dictionnaire. Donc, si vous avez un dictionnaire que vous souhaitez convertir en objet dynamique. Ensuite, dans votre modèle *.cshtml, les espaces réservés ressemblent à ceci : @Model.Name, au lieu de cela : @Model["Name"].

39voto

Rich N Points 1290

J'ai essayé de faire cela en une seule instruction avec une fonction de réduction (Aggregate en Linq). Le code ci-dessous fait la même chose que la réponse acceptée:

var dict = new Dictionary { { "Property", "foo" } };
dynamic eo = dict.Aggregate(new ExpandoObject() as IDictionary,
                            (a, p) => { a.Add(p); return a; });
string value = eo.Property;

11voto

Nicolas Tyler Points 1670

Si vous avez une classe que vous voulez convertir le dictionnaire aussi, vous pouvez utiliser ce qui suit pour convertir un dictionnaire en un objet de cette classe :

Exemple de classe :

public class Properties1
{
    public string Property { get; set; }
}

La solution :

JavaScriptSerializer serializer = new JavaScriptSerializer();
Dictionary dict = new Dictionary { { "Property", "foo" } };
Properties1 properties = serializer.ConvertToType<Properties1>(dict);
string value = properties.Property;

Vous pouvez également utiliser une méthode comme celle-ci pour construire l'objet à partir du dictionnaire, évidemment cela nécessite également que vous ayez une classe.

private static T DictionaryToObject(IDictionary dict) where T : new()
{
    T t = new T();
    PropertyInfo[] properties = t.GetType().GetProperties();

    foreach (PropertyInfo property in properties)
    {
        if (!dict.Any(x => x.Key.Equals(property.Name, 
            StringComparison.InvariantCultureIgnoreCase)))
            continue;
        KeyValuePair item = dict.First(x => x.Key.Equals(property.Name,
            StringComparison.InvariantCultureIgnoreCase));
        Type tPropertyType = t.GetType().GetProperty(property.Name).PropertyType;
        Type newT = Nullable.GetUnderlyingType(tPropertyType) ?? tPropertyType;
        object newA = Convert.ChangeType(item.Value, newT);
        t.GetType().GetProperty(property.Name).SetValue(t, newA, null);
    }
    return t;
}

Cependant, si vous n'avez pas la classe, vous pouvez créer un objet dynamique à partir d'un dictionnaire comme ceci :

private static dynamic DictionaryToObject(Dictionary dict)
{
    IDictionary eo = (IDictionary)new ExpandoObject();
    foreach (KeyValuePair kvp in dict)
    {
        eo.Add(kvp);
    }
    return eo;
}

Vous pouvez l'utiliser comme ceci :

Dictionary dict = new Dictionary {{ "Property", "foo" }};
dynamic properties = DictionaryToObject(dict);
string value = properties.Property;

9voto

Geir Sagberg Points 436

Légèrement plus modulaire version de la réponse de svick, en utilisant quelques méthodes d'extension :

public static class Extensions
{
    public static void AddRange(this ICollection collection, IEnumerable items)
    {
        foreach (var item in items)
        {
            collection.Add(item);
        }
    }

    public static dynamic ToDynamicObject(this IDictionary source)
    {
        ICollection> someObject = new ExpandoObject();
        someObject.AddRange(source);
        return someObject;
    }
}

4voto

ogggre Points 998

Le code ci-dessous gère les sous-dictionnaires et les convertit également en objets dynamiques imbriqués :

[return: NotNullIfNotNull(nameof(dictionary))]
static dynamic? ToDynamic(IReadOnlyDictionary? dictionary) =>
    dictionary?.Aggregate(
        (IDictionary)new ExpandoObject(),
        (obj, i) =>
        {
            if (i.Value is IReadOnlyDictionary nestedDictionary)
                obj.Add(new(i.Key, ToDynamic(nestedDictionary)));
            else
                obj.Add(i);
            return obj;
        });

Cette approche vous permet d'accéder au contenu des dictionnaires imbriqués simplement en accédant à l'objet dynamique lui-même :

var record = ToDynamic(...);
string cityName = record.city.name;

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X