微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

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");

原文地址:https://www.jb51.cc/c/116519.html

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐