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

但上面假设我在编译时知道属性(例如Age,Name).

假设我直到跑步时才知道它们会是什么.

如何更改上面的内容支持我在运行时才知道的属性

基本上我认为我问的是我如何调用直接调用TrySetMember的代码,以便它创建一个属性或使用getter / setter(如果已定义).

最终解决方案如下: –

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,null),CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None,object>>.Create(binder);

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

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

        return true;
    }
}

解决方法

虽然c#编译器正在使用字符串名称将动态关键字使用转换为dlr,但如果没有编译器帮助,那些Apis很难直接使用.开源框架 Dynamitey(通过nuget作为PCL库提供)封装了dlr API,使其变得简单,以便您可以调用 Impromptu.InvokeSet(target,name,value).
using Dynamitey;
...

dynamic o = MyNewObject();

Dynamic.InvokeSet(o,"Age",87); 
Dynamic.InvokeSet(o,"Names","Same);

Getters和Setter是直接使用实际Microsft API最简单的,所以如果你不想使用第三方框架,那么source也是一个选项.

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

dynamic o = MyNewObject();
var binder = Binder.SetMember(CSharpBinderFlags.None,typeof(object),new List<CSharpArgumentInfo>{
                           CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None,null)
                                               });

  var callsite = CallSite<Func<CallSite,object>>.Create(binder);

  callsite.Target(callsite,o,87);

  var binder2 =Binder.SetMember(CSharpBinderFlags.None,"Name",null)
                                               });
  var callsite2 = CallSite<Func<CallSite,object>>.Create(binder2);

  callsite2.Target(callsite2,"Sam");

相关文章

本程序的编译和运行环境如下(如果有运行方面的问题欢迎在评...
水了一学期的院选修,万万没想到期末考试还有比较硬核的编程...
补充一下,先前文章末尾给出的下载链接的完整代码含有部分C&...
思路如标题所说采用模N取余法,难点是这个除法过程如何实现。...
本篇博客有更新!!!更新后效果图如下: 文章末尾的完整代码...
刚开始学习模块化程序设计时,估计大家都被形参和实参搞迷糊...