Fügen Sie zur Laufzeit dynamisch C # -Eigenschaften hinzu

87

Ich weiß, dass es einige Fragen gibt, die sich damit befassen, aber die Antworten folgen normalerweise der Empfehlung eines Wörterbuchs oder einer Sammlung von Parametern, was in meiner Situation nicht funktioniert.

Ich benutze eine Bibliothek, die durch Reflexion arbeitet, um viele clevere Dinge mit Objekten mit Eigenschaften zu tun. Dies funktioniert sowohl mit definierten als auch mit dynamischen Klassen. Ich muss noch einen Schritt weiter gehen und etwas in diese Richtung tun:

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;

}

Die Bibliothek funktioniert gut mit einem dynamischen Variablentyp, dessen Eigenschaften manuell zugewiesen werden. Ich weiß jedoch nicht, wie viele oder welche Eigenschaften vorher hinzugefügt werden.

Paul Grimshaw
quelle

Antworten:

104

Haben Sie sich ExpandoObject angesehen?

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

Von MSDN:

Mit der ExpandoObject-Klasse können Sie zur Laufzeit Mitglieder ihrer Instanzen hinzufügen und löschen sowie Werte dieser Mitglieder festlegen und abrufen. Diese Klasse unterstützt die dynamische Bindung, mit der Sie die Standardsyntax wie sampleObject.sampleMember anstelle einer komplexeren Syntax wie sampleObject.GetAttribute ("sampleMember") verwenden können.

So können Sie coole Dinge tun wie:

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

dynObject.SomeDynamicAction(dynObject.SomeDynamicProperty);

Basierend auf Ihrem tatsächlichen Code könnten Sie mehr interessiert sein an:

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

Auf diese Weise brauchen Sie nur:

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

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

Wenn Sie von DynamicObject ableiten, können Sie eine eigene Strategie für die Bearbeitung dieser dynamischen Mitgliederanforderungen entwickeln. Achten Sie darauf, dass hier Monster vorhanden sind: Der Compiler kann nicht viele Ihrer dynamischen Aufrufe überprüfen, und Sie erhalten keine Intelligenz. Behalten Sie also einfach bei das im Kopf.

Clint
quelle
38

Danke @Clint für die tolle Antwort:

Ich wollte nur hervorheben, wie einfach es ist, dies mit dem Expando-Objekt zu lösen:

    var dynamicObject = new ExpandoObject() as IDictionary<string, Object>;
    foreach (var property in properties) {
        dynamicObject.Add(property.Key,property.Value);
    }
Paul Grimshaw
quelle
10
+1. Anmerkung: Warum geben Sie kein Wörterbuch statt dynamisch zurück? (im geringsten IDictionary)? Ich meine, die Rückgabe von Dynamik ist ein wenig "irreführend", da Sie immer ein Wörterbuch zurückgeben.
Veverke
Die Antwort wurde bearbeitet, wodurch Veverkes Bemerkung abgestanden ist.
DharmaTurtle
3

Sie können Ihre JSON-Zeichenfolge in ein Wörterbuch deserialisieren, neue Eigenschaften hinzufügen und dann serialisieren.

 var jsonString = @"{}";

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

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

        Console.WriteLine(JsonSerializer.Serialize(jsonDoc));
Khurshid Ali
quelle