通过路径访问嵌套结构(即“Model.NestedModel.ListOfThings[1]”)
本文关键字:ListOfThings NestedModel Model 访问 路径 嵌套 结构 | 更新日期: 2023-09-27 18:37:22
给定以下类和数据:
public class InnerExample
{
public string Inner1 { get; set; }
}
public class Example
{
public string Property1 { get; set; }
public string Property2 { get; set; }
public List<InnerExample> Inner { get; set; }
}
var a = new Example
{
Property1 = "Foo",
Property2 = "Bar",
Inner = new List<InnerExample>
{
new InnerExample
{
Inner1 = "This is the value to change"
}
}
};
有没有办法通过路径访问最里面的数据?
有什么办法可以说...
a["Inner[0].Inner1"] = "New value"
在这种特殊情况下,我知道我永远不会访问不存在的密钥,所以我并不过分担心错误检查。
(对不起,如果之前有人问过这个问题。 我做了一些搜索,但很快就用完了可以尝试的关键字。
没有内置的东西,但可以做到(即使它不会是微不足道的)。
您想要的是将索引器添加到类Example
。在索引器中,必须将提供的"属性路径"解析为步骤,并使用反射逐步解析目标属性。
例如,在将Inner[0].Inner1
解析为三个不同的步骤(获取Inner
,然后从该获取[0]
,然后从该Inner1
)解析后,您将得到一个类似于这样的循环:
// This works only with plain (non-indexed) properties, no error checking, etc.
object target = this;
PropertyInfo pi = null;
foreach (var step in steps)
{
pi = target.GetType().GetProperty(step);
target = pi.GetValue(target);
}
// And now you can either return target (on a get) or use pi.SetValue (on a set)
多亏了你给我的基本建议,乔恩,我想出了一个适合我的情况的解决方案。
- 没有错误检查
- 您必须设置属性,而不是数组元素。
-
我相信有更有效的方法可以做到这一点...我远不是反思专家。
/// <summary> /// Take an extended key and walk through an object to update it. /// </summary> /// <param name="o">The object to update</param> /// <param name="key">The key in the form of "NestedThing.List[2].key"</param> /// <param name="value">The value to update to</param> private static void UpdateModel(object o, string key, object value) { // TODO: // Make the code more efficient. var target = o; PropertyInfo pi = null; // Split the key into bits. var steps = key.Split('.').ToList(); // Don't walk all the way to the end // Save that for the last step. var lastStep = steps[steps.Count-1]; steps.RemoveAt(steps.Count-1); // Step through the bits. foreach (var bit in steps) { var step = bit; string index = null; // Is this an indexed property? if (step.EndsWith("]")) { // Extract out the value of the index var end = step.IndexOf("[", System.StringComparison.Ordinal); index = step.Substring(end+1, step.Length - end - 2); // and trim 'step' back down to exclude it. (List[5] becomes List) step = step.Substring(0, end); } // Get the new target. pi = target.GetType().GetProperty(step); target = pi.GetValue(target); // If the target had an index, find it now. if (index != null) { var idx = Convert.ToInt16(index); // The most generic way to handle it. var list = (IEnumerable) target; foreach (var e in list) { if (idx ==0) { target = e; break; } idx--; } } } // Now at the end we can apply the last step, // actually setting the new value. if (pi != null || steps.Count == 0) { pi = target.GetType().GetProperty(lastStep); pi.SetValue(target, value); } }