C# 按路径访问嵌套结构(即“Model.NestedModel.ListOfThings[1]”)
鉴于以下类别和数据:C# 按路径访问嵌套结构(即“Model.NestedModel.ListOfThings[1]”),c#,c#-4.0,nested,C#,C# 4.0,Nested,鉴于以下类别和数据: 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; } } va
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"
}
}
};
在这个特殊的例子中,我知道我永远不会访问一个不存在的密钥,所以我不太关心错误检查
(如果以前有人问过这个问题,很抱歉。我做了一些搜索,但很快就没有关键字了。)没有内置的功能,但也可以这样做(尽管它不会很琐碎) 您要做的是向类添加一个
示例
。在索引器中,您必须将提供的“属性路径”解析为多个步骤,并使用这些步骤逐步解析目标属性
例如,在将internal[0].Inner1
解析为三个不同的步骤(获取internal
,然后从该获取[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); } }
// ///获取扩展关键点并遍历对象以更新它。 /// ///要更新的对象 ///“NestedThing.List[2].key”形式的键 ///要更新到的值 私有静态void UpdateModel(对象o、字符串键、对象值) { //待办事项: //使代码更高效。 var目标=o; PropertyInfo pi=null; //把钥匙分成几位。 var steps=key.Split('.').ToList(); //不要走到尽头 //把它留到最后一步。 var lastStep=steps[steps.Count-1]; 步骤。移除(步骤。计数-1); //逐字逐句。 foreach(步进变量位) { var步长=位; 字符串索引=null; //这是索引属性吗? if(步骤结束(“]”) { //提取出索引的值 var end=step.IndexOf(“[”,System.StringComparison.Ordinal); 索引=步长子串(结束+1,步长-结束-2); //并向下修剪“台阶”以排除它。(列表[5]变为列表) 步骤=步骤子字符串(0,结束); } //找到新的目标。 pi=target.GetType().GetProperty(步骤); 目标=pi.GetValue(目标); //如果目标有索引,请立即查找。 如果(索引!=null) { var idx=转换为16(索引); //最通用的处理方法。 变量列表=(IEnumerable)目标; foreach(列表中的变量e) { 如果(idx==0) { 目标=e; 打破 } idx-; } } } //现在我们可以应用最后一步, //实际设置新值。 if(pi!=null | |步数.计数==0) { pi=target.GetType().GetProperty(最后一步); pi.设定值(目标、值); } }
/// <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);
}
}