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

89

Je sais qu'il y a des questions qui traitent de cela, mais les réponses suivent généralement le type de recommandation d'un dictionnaire ou d'une collection de paramètres, ce qui ne fonctionne pas dans ma situation.

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

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 très bien avec un type de variable dynamique, avec des propriétés attribuées manuellement. Cependant, je ne sais pas combien ou quelles propriétés seront ajoutées au préalable.

Paul Grimshaw
la source

Réponses:

105

Avez-vous jeté un œil à ExpandoObject?

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

Depuis MSDN:

La classe ExpandoObject vous permet d'ajouter et de supprimer des membres de ses instances au moment 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 sympas 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 pourriez ê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 proposer votre propre stratégie pour gérer ces demandes de membres dynamiques, attention il y a des monstres ici: le compilateur ne pourra pas vérifier beaucoup de vos appels dynamiques et vous n'obtiendrez pas d'intellisense, alors continuez cela à l'esprit.

Clint
la source
39

Merci @Clint pour la bonne réponse:

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

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

vous pouvez désérialiser votre chaîne json dans un dictionnaire, puis ajouter de nouvelles propriétés, puis la sérialiser.

 var jsonString = @"{}";

        var jsonDoc = JsonSerializer.Deserialize<Dictionary<string, object>>(jsonString);

        jsonDoc.Add("Name", "Khurshid Ali");

        Console.WriteLine(JsonSerializer.Serialize(jsonDoc));
Khurshid Ali
la source