gpt4 book ai didi

C# DynamicObject 动态属性

转载 作者:太空狗 更新时间:2023-10-29 18:15:06 26 4
gpt4 key购买 nike

假设我不能使用 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 的代码,以便它创建一个新属性或使用 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,
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;
}
}

最佳答案

虽然 c# 编译器将动态关键字用法转换为使用字符串名称的 dlr 调用,但如果没有编译器的帮助,这些 Api 很难直接使用。开源框架Dynamitey (通过 nuget 作为 PCL 库提供)封装了 dlr API,以便于您只需调用 Impromptu.InvokeSet(target, name, value) .

using Dynamitey;
...

dynamic o = MyNewObject();

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

Getter 和 Setter 是直接使用实际 Microsoft API 最简单的方法,因此如果您不想使用第 3 方框架,请转至 source也是一种选择。

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

dynamic o = MyNewObject();
var binder = Binder.SetMember(CSharpBinderFlags.None,
"Age",
typeof(object),
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,o,87);

var binder2 =Binder.SetMember(CSharpBinderFlags.None,
"Name",
typeof(object),
new List<CSharpArgumentInfo>{
CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null),
CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null)
});
var callsite2 = CallSite<Func<CallSite, object, object, object>>.Create(binder2);

callsite2.Target(callsite2,o,"Sam");

没有StackOverflow,没有什么可以改进的

关于C# DynamicObject 动态属性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12057516/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com