Aggiungi dinamicamente proprietà C # in fase di esecuzione


89

So che ci sono alcune domande che affrontano questo problema, ma le risposte di solito seguono la falsariga di consigliare un dizionario o una raccolta di parametri, che non funziona nella mia situazione.

Sto usando una libreria che funziona attraverso la riflessione per fare molte cose intelligenti con oggetti con proprietà. Funziona con classi definite e classi dinamiche. Devo fare un ulteriore passo avanti e fare qualcosa in questo senso:

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 libreria funziona bene con un tipo di variabile dinamica, con proprietà assegnate manualmente. Tuttavia non so quante o quali proprietà verranno aggiunte in anticipo.

Risposte:


105

Hai dato un'occhiata a ExpandoObject?

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

Da MSDN:

La classe ExpandoObject consente di aggiungere ed eliminare membri delle sue istanze in fase di esecuzione e anche di impostare e ottenere i valori di questi membri. Questa classe supporta l'associazione dinamica, che consente di utilizzare la sintassi standard come sampleObject.sampleMember invece di una sintassi più complessa come sampleObject.GetAttribute ("sampleMember").

Permettendoti di fare cose interessanti come:

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

dynObject.SomeDynamicAction(dynObject.SomeDynamicProperty);

In base al tuo codice effettivo potresti essere più interessato a:

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;
        }
    }
}

In questo modo hai solo bisogno di:

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

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

Derivare da DynamicObject ti consente di elaborare la tua strategia per gestire queste richieste di membri dinamici, fai attenzione che qui ci saranno dei mostri: il compilatore non sarà in grado di verificare molte delle tue chiamate dinamiche e non otterrai intellisense, quindi mantieni questo in mente.


39

Grazie @Clint per l'ottima risposta:

Volevo solo evidenziare quanto sia stato facile risolvere questo problema utilizzando l'oggetto Expando:

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

3

potresti deserializzare la tua stringa json in un dizionario e quindi aggiungere nuove proprietà, quindi serializzarla.

 var jsonString = @"{}";

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

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

        Console.WriteLine(JsonSerializer.Serialize(jsonDoc));
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.