web-dev-qa-db-fra.com

Ajouter dynamiquement des propriétés C # au moment de l'exécution

Je sais que certaines questions abordent ce sujet, mais les réponses vont généralement dans le sens de la recommandation d'un dictionnaire ou d'une collection de paramètres, ce qui ne fonctionne pas dans mon cas.

J'utilise une bibliothèque qui fonctionne par réflexion pour faire plein de choses intelligentes avec des objets dotés de propriétés. Cela fonctionne avec des classes définies, ainsi que des classes dynamiques. Je dois aller plus loin et faire quelque chose dans ce sens:

public static object GetDynamicObject(Dictionary<string,object> properties) {
    var myObject = new object();
    foreach (var property in properties) {
        //This next line obviously doesn't work... 
        myObject.AddProperty(property.Key,property.Value);
    }
    return myObject;
}

public void Main() {
    var properties = new Dictionary<string,object>();
    properties.Add("Property1",aCustomClassInstance);
    properties.Add("Property2","TestString2");

    var myObject = GetDynamicObject(properties);

    //Then use them like this (or rather the plug in uses them through reflection)
    var customClass = myObject.Property1;
    var myString = myObject.Property2;

}

La bibliothèque fonctionne bien avec un type de variable dynamique, avec des propriétés assignées manuellement. Cependant, je ne sais pas combien ou quelles propriétés seront ajoutées auparavant.

77
Paul Grimshaw

Avez-vous jeté un coup d’œil à ExpandoObject?

voir: http://blogs.msdn.com/b/csharpfaq/archive/2009/10/01/dynamic-in-c-4-0-introducing-the-expandoobject.aspx

De MSDN:

La classe ExpandoObject vous permet d'ajouter et de supprimer des membres de ses instances lors de l'exécution, ainsi que de définir et d'obtenir les valeurs de ces membres. Cette classe prend en charge la liaison dynamique, ce qui vous permet d'utiliser une syntaxe standard telle que sampleObject.sampleMember au lieu d'une syntaxe plus complexe telle que sampleObject.GetAttribute ("sampleMember").

Vous permettant de faire des choses cool comme:

dynamic dynObject = new ExpandoObject();
dynObject.SomeDynamicProperty = "Hello!";
dynObject.SomeDynamicAction = (msg) =>
    {
        Console.WriteLine(msg);
    };

dynObject.SomeDynamicAction(dynObject.SomeDynamicProperty);

En fonction de votre code actuel, vous serez peut-être plus intéressé par:

public static dynamic GetDynamicObject(Dictionary<string, object> properties)
{
    return new MyDynObject(properties);
}

public sealed class MyDynObject : DynamicObject
{
    private readonly Dictionary<string, object> _properties;

    public MyDynObject(Dictionary<string, object> properties)
    {
        _properties = properties;
    }

    public override IEnumerable<string> GetDynamicMemberNames()
    {
        return _properties.Keys;
    }

    public override bool TryGetMember(GetMemberBinder binder, out object result)
    {
        if (_properties.ContainsKey(binder.Name))
        {
            result = _properties[binder.Name];
            return true;
        }
        else
        {
            result = null;
            return false;
        }
    }

    public override bool TrySetMember(SetMemberBinder binder, object value)
    {
        if (_properties.ContainsKey(binder.Name))
        {
            _properties[binder.Name] = value;
            return true;
        }
        else
        {
            return false;
        }
    }
}

De cette façon, vous avez juste besoin de:

var dyn = GetDynamicObject(new Dictionary<string, object>()
    {
        {"prop1", 12},
    });

Console.WriteLine(dyn.prop1);
dyn.prop1 = 150;

Dériver de DynamicObject vous permet de définir votre propre stratégie de traitement de ces demandes de membres dynamiques. Méfiez-vous des monstres: le compilateur va pas être capable de vérifier beaucoup de vos appels dynamiques et vous n’obtiendrez pas d’intellisense, alors gardez cela à l’esprit.

91
Clint

Merci @Clint pour la bonne réponse:

Je voulais juste souligner à quel point il était facile de résoudre ce problème à l'aide de l'objet Expando:

    var dynamicObject = new ExpandoObject() as IDictionary<string, Object>;
    foreach (var property in properties) {
        dynamicObject.Add(property.Key,property.Value);
    }
32
Paul Grimshaw