2012-07-24 104 views
2

給定一個類序列化對象成扁平字典<字符串,字符串>

public class MyClass 
{ 
    public MyInnerClass Property1 {get;set;} 
    public MyInnerClass2 Field1 
    public MyInnnerClass[] Property2 {get;set;} 
} 

我需要串行化,沒有什麼不同MVC串行上述序列化到下面的字典。

new { 
     { 
      "Property1.InnerField", "1", 
     }, 
     { 
      "Field1.InnerProperty", "7/7/2007" 
     }, 
     { 
      "Property2[0].InnerProperty", "0" 
     }, 
     { 
      "Property2[1].InnerProperty", "1" 
     } 
} 

基本上它需要位置和本地值,或進一步遞進,直到它找到一個非引用類型。

回答

3

談到你的問題,我們可能會把答案放在教導的方式,只是排除任何存在的序列化架構。這樣你就可以完全自由地進入對象引用樹,而不用費力使用反射並填充結果字典。

我們需要一個簡單的方法來訪問給定的對象,然後爲每個公共屬性遞歸地調用它自己。簽名應該包含一個字符串,表示至少是當前的父鏈(例如:"Property1.InnerProperty4.InnerProperty7"),返回類型應該是Dictionary<string,string>,只有來自當前和嵌套對象的東西。 在開始時它應該檢查參數是否爲值類型,在前一種情況下只需創建一個新的字典,添加一個新的KeyValuePair(parent + name,value)並返回;而在後一種情況下,創建一個新的Dictionary,然後foreach公共屬性調用本身傳遞當前屬性,父+名稱字符串並將返回的字典與先前創建的字典連接起來,並在循環結束時返回此大字典。我們可以在開始時檢查傳遞的對象是否實現類似於IEnumerable接口的東西。在這種情況下,不要循環遍歷其成員,而是遍歷其索引器並調用每個項目的方法。

我發現時間來執行我昨天所描述的。這裏有一個遞歸方法,用於返回給定對象的(公共屬性全名) - (值)對的字典。當然,它可能並不完全詳細說明你想要達成的目標,但是你會發現很多技巧,想法和概念來組成你自己的:

namespace MyNamespace 
{ 
    public class ClassA { 
     int p1 = 1; 
     string p2 = "abcdef"; 
     List<string> p3 = new List<string>() { "ghi","lmn" }; 
     ClassB p4 = new ClassB(); 
     ClassB p5 = null; 

     public int PA1 { get { return p1; } } 
     public string PA2 { get { return p2; } } 
     public List<string> PA3 { get { return p3; } } 
     public ClassB PA4 { get { return p4; } } 
     public ClassB PA5 { get { return p5; } } 
    } 

    public class ClassB{ 
     private string p1 = "zeta"; 
     public string PB1 { get { return p1; } } 
    } 

    public class Program { 

     public void Main() 
     { 
      ClassA o = new ClassA(); 
      Dictionary<string, string> result = GetPropertiesDeepRecursive(o, "[o]", new List<string>() { "MyNamespace" }); 
     } 

     /// <summary> 
     /// Returns a dictionary of propertyFullname-value pairs of the given object (and deep recursively for its public properties) 
     /// note: it's object oriented (on purpose) and NOT type oriented! so it will just return values of not null object trees 
     /// <param name="includedNamespaces">a list of full namespaces for whose types you want to deep search in the tree</param> 
     /// </summary>   
     public Dictionary<string, string> GetPropertiesDeepRecursive(object o, string memberChain, List<string> includedNamespaces) 
     { 

      List<string> types_to_exclude_by_design = new List<string>() { "System.string", "System.String" }; 

      //the results bag 
      Dictionary<string, string> r = new Dictionary<string, string>(); 

      //if o is null just return value = [null] 
      if (o == null) 
      { 
       r.Add(memberChain, "[null]"); 
       return r; 
      } 

      //the current object argument type 
      Type type = o.GetType(); 

      //reserve a special treatment for specific types by design (like string -that's a list of chars and you don't want to iterate on its items) 
      if (types_to_exclude_by_design.Contains(type.FullName)) 
      { 
       r.Add(memberChain, o.ToString()); 
       return r; 
      } 

      //if the type implements the IEnumerable interface... 
      bool isEnumerable = 
       type 
       .GetInterfaces() 
       .Any(t => t == typeof(System.Collections.IEnumerable)); 
      if (isEnumerable) 
      { 
       int i_item = 0; 
       //loop through the collection using the enumerator strategy and collect all items in the result bag 
       //note: if the collection is empty it will not return anything about its existence, 
       //  because the method is supposed to catch value items not the list itself     
       foreach (object item in (System.Collections.IEnumerable)o) 
       { 
        string itemInnerMember = string.Format("{0}[{1}]", memberChain, i_item++); 
        r = r.Concat(GetPropertiesDeepRecursive(item, itemInnerMember, includedNamespaces)).ToDictionary(e => e.Key, e => e.Value); 
       } 
       return r; 
      } 

      //here you need a strategy to exclude types you don't want to inspect deeper like int,string and so on 
      //in those cases the method will just return the value using the specific object.ToString() implementation 
      //now we are using a condition to include some specific types on deeper inspection and exclude all the rest 
      if (!includedNamespaces.Contains(type.Namespace)) 
      { 
       r.Add(memberChain, o.ToString()); 
       return r; 
      } 

      //otherwise go deeper in the object tree...    
      //and foreach object public property collect each value 
      PropertyInfo[] pList = type.GetProperties(); 
      foreach (PropertyInfo p in pList) 
      { 
       object innerObject = p.GetValue(o, null); 
       string innerMember = string.Format("{0}.{1}", memberChain, p.Name); 
       r = r.Concat(GetPropertiesDeepRecursive(innerObject, innerMember, includedNamespaces)).ToDictionary(e => e.Key, e => e.Value); 
      } 
      return r; 
     } 
    } 
} 
+0

Diego,沒關係。我之前做過這個,但是我失去了那個代碼。在MVC庫中的某個人必須實現這一點。如果可能的話,我想抓取並重用。所以是的,我只是問在已經寫好的大型互聯網中是否有可用的解決方案。我可以重新實施它沒有問題,但有點按時間。 – Alwyn 2012-07-25 01:34:44

+0

哦,你真的不該有的人。我期待有人把我指向一個不是從頭開始構建的MVC類庫。但是這超出了這一點 - 非常感謝。 – Alwyn 2012-07-25 14:14:21

相關問題