Dynamische Eigenschaften von C # DynamicObject

Angenommen, ich kann kein ExpandoObject verwenden und muss mein eigenes wie folgt rollen:

class MyObject : DynamicObject {
    dictionary<string, object> _properties = dictionary<string, object>();

    public override bool TryGetMember(GetMemberBinder binder, out object result) {
        string name = binder.Name.ToLower();

        return _properties.TryGetValue(name, out result);
    }

    public override bool TrySetMember(SetMemberBinder binder, object value) {
        _properties[binder.Name.ToLower()] = value;

        return true;
    }
}

und weiter unten die Klassenhierarchie, die ich habe

class MyNewObject : MyObject {
    public string Name {
        get {
            // do some funky stuff
        }
        set {
            // ditto
        }
    }
}

Das ist ganz nett, da ich jetzt folgendes machen kann: -

dynamic o = MyNewObject();

o.Age = 87;     // dynamic property, handled by TrySetMember in MyObject
o.Name = "Sam"; // non dynamic property, handled by the setter defined in MyNewObject

Es wird jedoch davon ausgegangen, dass ich die Eigenschaften (z. B. Alter, Name) zum Zeitpunkt der Kompilierung kenne.

Angenommen, ich weiß nicht, was sie bis zur Laufzeit sein werden.

Wie kann ich die obigen Einstellungen ändern, um Eigenschaften zu unterstützen, die mir nur zur Laufzeit bekannt sind?

Grundsätzlich frage ich mich, wie ich den Code aufrufen kann, der TrySetMember direkt aufruft, so dass entweder eine neue Eigenschaft erstellt oder ein Getter / Setter verwendet wird, wenn eines definiert wurde.

Endgültige Lösung wie folgt:

using System.Dynamic;
using Microsoft.CSharp.RuntimeBinder;
using System.Runtime.CompilerServices;

class MyObject : DynamicObject {
    Dictionary<string, object> _properties = new Dictionary<string, object>();

    public object GetMember(string propName) {
        var binder = Binder.GetMember(CSharpBinderFlags.None,
              propName, this.GetType(),
              new List<CSharpArgumentInfo>{
                       CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null)});
        var callsite = CallSite<Func<CallSite, object, object>>.Create(binder);

        return callsite.Target(callsite, this);
    }

    public void SetMember(string propName, object val) {
        var binder = Binder.SetMember(CSharpBinderFlags.None,
               propName, this.GetType(),
               new List<CSharpArgumentInfo>{
                       CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null),
                       CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null)});
        var callsite = CallSite<Func<CallSite, object, object, object>>.Create(binder);

        callsite.Target(callsite, this, val);
    }

    public override bool TryGetMember(GetMemberBinder binder, out object result) {
        string name = binder.Name.ToLower();

        return _properties.TryGetValue(name, out result);
    }

    public override bool TrySetMember(SetMemberBinder binder, object value) {
        _properties[binder.Name.ToLower()] = value;

        return true;
    }
}

Antworten auf die Frage(2)

Ihre Antwort auf die Frage