2013-10-30 95 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

謝謝。這讓我走上了我自己的解決方案之路,這是我在這裏發佈的。 –