C # DynamicObject динамические свойства
Предполагая, что я не могу использовать ExpandoObject и мне нужно свернуть свое собственное так:
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;
}
}
и дальше вниз по иерархии классов у меня есть
class MyNewObject : MyObject {
public string Name {
get {
// do some funky stuff
}
set {
// ditto
}
}
}
что довольно приятно, так как теперь я могу сделать следующее:
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
Но вышеизложенное предполагает, что я знаю свойства (например, возраст, имя) во время компиляции.
Предположим, я не знаю, какими они будут до времени выполнения.
Как я могу изменить вышеперечисленное для поддержки свойств, которые я буду знать только во время выполнения?
По сути, я думаю, что я спрашиваю, как я могу вызвать код, который напрямую вызывает TrySetMember, чтобы он либо создал новое свойство, либо использовал метод получения / установки, если он был определен.
Final Solution as follows :-
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;
}
}