2013-10-30 61 views
0

鉴于以下类和数据:通过访问路径的嵌套结构(即,“Model.NestedModel.ListOfThings [1]”)

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" 

在这种特殊情况下,我知道一个事实,我将永远不会被访问一个不存在的关键,所以我并不过于担心关于错误检查。

(很抱歉,如果这已被问过,我做了一些搜索,但很快跑出来的关键字去尝试。)

回答

0

得益于你给我的基本建议,乔恩,我想出了一个适用于我的案例的解决方案。

  • 没有错误检查
  • 您必须设置属性,而不是一个数组元素。
  • 我敢肯定有更高效的方法来做到这一点...我远离反思专家。

    /// <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); 
        } 
    } 
    
0

没有什么内置的,但它是可以做到的(即使它不会微不足道)。

你想要的是添加一个indexerExample。在索引器中,您必须将提供的“属性路径”解析为步骤,并使用reflection逐步解析目标属性。

例如,解析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) 
+0

谢谢。这让我走上了我自己的解决方案之路,这是我在这里发布的。 –