使用反射获取到特定键的字典完整路径
本文关键字:字典 路径 反射 获取 | 更新日期: 2023-09-27 18:03:51
我有一个嵌套的IDictionary
,像这样;
class SomeObject {
public IDictionary<string, IDictionary<string, decimal>> Entries { get; set; }
}
一个对象可能是这样的;
var o = new SomeObject {
Entries = new ... {
["first"] = new ... {
["a"] = 1.0,
["b"] = 2.0
},
["second"] = new ... {
}
}
};
我试图找出如何获得"路径"到一个嵌套的键作为string
s使用lambda表达式的集合。例如:
class SomeFactory {
public SomeFactory Use<T>(T entity) {
this.Model = entity; return this;
}
public IEnumerable<string> Get<TProperty>(Expression<Func<T, IEnumerable<TProperty>>> selector) {
var properties = ... // get list of properties from [selector] //
}
}
var factory = new SomeFactory();
var list = factory.Use<SomeObject>(o).Get(n => n.Entries["first"]["b"]);
其中结果将是具有值的IEnumerable<string>
…{"Entries","first","b"}
.
这是可能的吗?
用例我想这样做的原因是因为我正在使用一个库,它可以使用一个对象以某种方式发出命令,看起来像这样(伪代码);
class Patch {
string Property;
object Value;
Patch[] Nested;
}
每个Patch
都可以取从给定点反序列化的对象上的1
属性名。它将对它执行一个非常快的操作,比从数据库加载整个对象、更新它并再次保存它要快得多。这在程序的各个部分都很重要,原因有很多。(这不是一个SQL数据库)
如果给出了nested
补丁,它将不设置顶级属性的值,而是查找顶级属性并将其用作执行数组中下一个Patch
的启动点。这个过程一直持续到最后一个,然后进行更改。
因此,为了向IDictionary
发布补丁,整个对象图需要看起来类似于…
{
"Property": "Entries",
"Nested": [
{
"Property": "first",
"Nested": [
{
"Property": "b",
"Value": 7.0
}
]
}
]
}
这不是问题,但每次都是一个很麻烦的图表。我的想法是使整个过程更简单,能够从一个lambda表达式构建这个图,在IDictionary
对象上找到所需的目的地;即f(n => n["first"]["b"])
下面的代码适合上面的场景:
public static IEnumerable<string> Get<T>(Expression<Func<T, object>> selector)
{
var list = new List<string>();
Expression exp = (selector.Body as UnaryExpression).Operand as MethodCallExpression;
while (exp is MethodCallExpression)
{
var call = exp as MethodCallExpression;
var arg = call.Arguments[0].ToString();
if(call.Arguments[0].Type == typeof(string))
{
arg = arg.Substring(1, arg.Length - 2);
}
list.Add(arg);
exp = call.Object as Expression;
}
var member = exp as MemberExpression;
list.Add(member.Member.Name);
list.Reverse();
return list;
}
static void Main(string[] args)
{
var graph = Get<SomeObject>(o => o.Entries["first"]["b"]);
foreach (var node in graph)
{
Console.WriteLine(node);
}
Console.ReadLine();
}
输出是:
条目首先b