2016-10-28 29 views
0

所以我有這個代碼應該遞歸地打印給定對象的所有屬性及其內容。迭代通過反射獲得的字典

static public void PrintProperties(object obj, int indent) 
{ 
    if (obj == null) return; 
    string indentString = new string(' ', indent); 
    Type objType = obj.GetType(); 
    PropertyInfo[] properties = objType.GetProperties(); 
    foreach (PropertyInfo property in properties) 
    { 
     object propValue = property.GetValue(obj, null); 
     if (property.PropertyType.Assembly == objType.Assembly && !property.PropertyType.IsEnum) 
     { 
      Console.WriteLine("{0}{1}:", indentString, property.Name); 
      PrintProperties(propValue, indent + 2); 
     } 
     else 
     { 
      if (null != propValue) 
      { 
       Type t = propValue.GetType(); 
       //Console.WriteLine(":::::{0}:::::", propValue.GetType()); 
       bool isDict = t.IsGenericType && t.GetGenericTypeDefinition() == typeof(Dictionary<,>); 
       if (isDict) 
       { 
        Type keyType = t.GetGenericArguments()[0]; 
        Type valueType = t.GetGenericArguments()[1]; 
        foreach (KeyValuePair<keyType, valueType> kvp in (Dictionary<keyType, valueType>)propValue) 
        { 
         Console.WriteLine(string.Format("Key = {0}, Value = {1}", kvp.Key, kvp.Value)); 
        } 
       } 
      } 

      Console.WriteLine("{0}{1}: {2}", indentString, property.Name, propValue); 
     } 
    } 
} 

它不適合ListDictionary工作呢,我工作的一部分Dictionary現在。

問題是,我提取鍵和值與類型:

Type keyType = t.GetGenericArguments()[0]; 
Type valueType = t.GetGenericArguments()[1]; 

但隨後VS2013告訴我,有一個與此行的一個問題:

foreach (KeyValuePair<keyType, valueType> kvp in (Dictionary<keyType, valueType>)propValue) 

它告訴我,未找到類型或名稱空間KeyType和valueType。 我錯過了什麼?

謝謝。

PS:.NET 4.5.1

+0

'keyType'&'valueType'在你的例子是Type'但'KeyValuePair的'實例中'需要一個類型名稱,使得類型可以在運行時評估。您必須使用非泛型「Dictionary」類訪問字典並手動投射鍵和值對象。 – Howwie

+1

[將C#中的所有對象轉儲到日誌的最佳方式是什麼?](http:// stackoverflow。com/questions/360277 /什麼是最好的方式轉儲整個對象到一個登錄在c) –

回答

1

在調用泛型方法你必須提供實際類型的名稱(或者通過從你自己的方法的定義泛型類型參數) - 不是Type實例。

+0

所以沒有辦法自動打印通過提取的字典的內容反射?因爲在'propValue'中,我可以看到鍵和值的類型(例如:'System.Collections.Generic.Dictionary 2 [Mobile.Fonct ionComptage.Modele.IndexFournisseur,System.String]') –

1

基本上你keyType & valueTypeType類型的變量,它在運行時已知的,所以你必須使用反射來投你propValue到適當的通用詞典。但是,您可以使用這樣的事實:爲了向後兼容,Dictionary<TKey,TValue>實現了非通用IDictionary接口。

因此,在特定情況下,將足以取代這個:

foreach (KeyValuePair<keyType, valueType> kvp in (Dictionary<keyType, valueType>)propValue) 

與此:

foreach (DictionaryEntry kvp in (IDictionary)propValue) 
1

由於decPL指出,你應該使用System.Collections.IDictionary。但是,你也應該改變你的isDict邏輯。 System.Type.IsAssignableFrom允許您檢查「指定類型的實例是否可以分配給當前類型實例」。這裏是顯示它的行爲的代碼。

using System; 
using System.Collections; 
using System.Collections.Generic; 

namespace ConsoleApplication1 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      Console.WriteLine("Testing System.Type.IsAssignableFrom"); 

      var propValue = new Dictionary<string, string>() { { "hello", "world" } }; 
      var t = propValue.GetType(); 
      bool isDict = typeof(IDictionary).IsAssignableFrom(t); 
      if (isDict) 
      { 
       foreach (DictionaryEntry kvp in (IDictionary)propValue) 
       { 
        Console.WriteLine(string.Format("Key = {0}, Value = {1}", kvp.Key, kvp.Value)); 
       } 
      } 

      Console.ReadLine(); 
     } 
    } 
} 

所以你的方法應該看起來像這樣。

static public void PrintProperties(object obj, int indent) 
{ 
    if (obj == null) return; 
    string indentString = new string(' ', indent); 
    Type objType = obj.GetType(); 
    PropertyInfo[] properties = objType.GetProperties(); 
    foreach (PropertyInfo property in properties) 
    { 
     object propValue = property.GetValue(obj, null); 
     if (property.PropertyType.Assembly == objType.Assembly && !property.PropertyType.IsEnum) 
     { 
      Console.WriteLine("{0}{1}:", indentString, property.Name); 
      PrintProperties(propValue, indent + 2); 
     } 
     else 
     { 
      if (null != propValue) 
      { 
       Type t = propValue.GetType(); 
       //Console.WriteLine(":::::{0}:::::", propValue.GetType()); 
       bool isDict = typeof(IDictionary).IsAssignableFrom(t); 
       if (isDict) 
       { 
        foreach (DictionaryEntry kvp in (IDictionary)propValue) 
        { 
         Console.WriteLine(string.Format("Key = {0}, Value = {1}", kvp.Key, kvp.Value)); 
        } 
       } 
      } 

      Console.WriteLine("{0}{1}: {2}", indentString, property.Name, propValue); 
     } 
    } 
} 

但是,您也可以使用C#作爲運算符來做到這一點。 as運算符將嘗試執行到指定類型的轉換。如果不可行,則返回null。一些示例代碼。

using System; 
using System.Collections; 
using System.Collections.Generic; 

namespace ConsoleApplication1 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      Console.WriteLine("Testing System.Type.IsAssignableFrom"); 

      var propValue = new Dictionary<string, string>() { { "hello", "world" } }; 
      IDictionary asDict = propValue as IDictionary; 
      if (asDict != null) 
      { 
       foreach (DictionaryEntry kvp in (IDictionary)propValue) 
       { 
        Console.WriteLine(string.Format("Key = {0}, Value = {1}", kvp.Key, kvp.Value)); 
       } 
      } 

      Console.ReadLine(); 
     } 
    } 
} 

和你的方法。

static public void PrintProperties(object obj, int indent) 
{ 
    if (obj == null) return; 
    string indentString = new string(' ', indent); 
    Type objType = obj.GetType(); 
    PropertyInfo[] properties = objType.GetProperties(); 
    foreach (PropertyInfo property in properties) 
    { 
     object propValue = property.GetValue(obj, null); 
     if (property.PropertyType.Assembly == objType.Assembly && !property.PropertyType.IsEnum) 
     { 
      Console.WriteLine("{0}{1}:", indentString, property.Name); 
      PrintProperties(propValue, indent + 2); 
     } 
     else 
     { 
      if (null != propValue) 
      { 
       var asDict = propValue as IDictionary; 
       if (asDict != null) 
       { 
        foreach (DictionaryEntry kvp in asDict) 
        { 
         Console.WriteLine(string.Format("Key = {0}, Value = {1}", kvp.Key, kvp.Value)); 
        } 
       } 
      } 

      Console.WriteLine("{0}{1}: {2}", indentString, property.Name, propValue); 
     } 
    } 
}