2012-07-27 78 views
1

我在C#中遇到System.Reflection的一些問題。我從數據庫中提取數據並以JSON字符串檢索數據。我已經使用Reflection將自己的JSON數據處理成我自己聲明的對象。然而,因爲我無意中得到一個JSON字符串和一個50到100個對象的數組,我的程序運行速度非常慢,因爲我正在使用反射循環。在將JSON字符串反序列化爲.NET對象時反射太慢

我聽說反射很慢,但它不應該這麼慢。我覺得有些東西在我的實現中是不正確的,因爲我有一個不同的項目,我使用JSON.NET序列化程序,並且實例化對象的方式與在同一輸出上運行得很好(不到一秒)的反射有點不同,而我的慢程序需要50個物體約10秒鐘。

下面是我classses,我使用存儲數據

class DC_Host 
{ 
    public string name; 

    public void printProperties() 
    { 
     //Prints all properties of a class usign reflection 
     //Doesn't really matter, since I'm not usign this for processing 
    } 
} 

class Host : DC_Host 
{ 
    public string asset_tag; 
    public string assigned; 
    public string assigned_to; 
    public string attributes; 
    public bool? can_print; 
    public string category; 
    public bool? cd_rom; 
    public int? cd_speed; 
    public string change_control; 
    public string chassis_type; 
    //And some more properties (around 70 - 80 fields in total) 

下面你會發現我的用於處理信息轉換成存儲在列表內的對象的方法。 JSON數據存儲在dictionairy中,該dictionairy包含JSON輸入中定義的每個數組對象的另一個詞典。對JSON進行反序列化發生在一個毫秒內,所以在那裏不應該有問題。

public List<DC_Host> readJSONTtoHost(ref Dictionary<string, dynamic> json) 
{ 
    bool array = isContainer(); 

    List<DC_Host> hosts = new List<DC_Host>(); 

    //Do different processing on objects depending on table type (array/single) 
    if (array) 
    { 
     foreach (Dictionary<string, dynamic> obj in json[json.First().Key]) 
     { 
      hosts.Add(reflectToObject(obj)); 
     } 
    } 
    else 
    { 
     hosts.Add(reflectToObject(json[json.First().Key])); 
    } 

    return hosts; 
} 

private DC_Host reflectToObject(Dictionary<string,dynamic> obj) 
{ 
    Host h = new Host(); 

    FieldInfo[] fields = h.GetType().GetFields(); 

    foreach (FieldInfo f in fields) 
    { 
     Object value = null; 

     /* IF there are values that are not in the dictionairy or where wrong conversion is 
     * utilised the values will not be processed and therefore not inserted into the 
     * host object or just ignored. On a later stage I might post specific error messages 
     * in the Catch module. */ 

     /* TODO : Optimize and find out why this is soo slow */ 
     try 
     { 
      value = obj[convTable[f.Name]]; 
     } 
     catch { } 

     if (value == null) 
     { 
      f.SetValue(h, null); 
      continue; 
     } 
     // Het systeem werkt met list containers, MAAAR dan mogen er geen losse values zijn dus dit hangt 
     // zeer sterk af van de implementatie van Service Now. 
     if (f.FieldType == typeof(List<int?>)) //Arrays voor strings,ints en bools dus nog definieren 
     { 
      int count = obj[convTable[f.Name]].Count; 
      List<int?> temp = new List<int?>(); 
      for (int i = 0; i < count; i++) 
      { 
       temp.Add(obj[convTable[f.Name]][i]); 
       f.SetValue(h, temp); 
      } 
     } 
     else if (f.FieldType == typeof(int?)) 
      f.SetValue(h, int.Parse((string)value)); 
     else if (f.FieldType == typeof(bool?)) 
      f.SetValue(h, bool.Parse((string)value)); 
     else 
      f.SetValue(h, (string)value); 
    } 

    Console.WriteLine("Processed " + h.name); 

    return h; 
} 

我不知道什麼JSON.NET的執行是在後臺使用反射,但我assumign他們用我丟失的東西優化其反射。

+0

爲了獲得最大性能,需要生成新代碼來填充數據。 – CodesInChaos 2012-07-27 07:48:36

+0

但是即使沒有這些,充分利用字典和緩存應該會提高代碼的速度。 – CodesInChaos 2012-07-27 07:50:33

+0

並擺脫空的捕獲。'TryGetValue' ftw – CodesInChaos 2012-07-27 07:51:16

回答

2

對於遇到這篇文章的人,我會在這裏發佈我的解決方案到我的問題。 這個問題並沒有真正與反思有關。有些方法可以通過像CodeInChaos和Marc Gravell這樣的反射來提高速度,Marc提供了一個非常有用的庫(FastMember),用於那些在低級反射方面沒有太多經驗的人。

然而,解決方案與反射本身無關。我有一個Try Catch語句來評估我的字典中是否存在值。使用try catch語句來處理程序流並不是一個好主意。處理異常對性能影響很大,特別是在運行調試器時,Try Catch語句可能會大大地降低性能。

//New implementation, use TryGetValue from Dictionary to check for excising values. 
dynamic value = null; 
obj.TryGetValue(convTable[f.Name], out value); 

我的程序現在運行完全正常,因爲我省略了TryCatch聲明。

3

基本上,像這樣的高性能代碼往往廣泛地使用元編程;很多ILGenerator等(或Expression/CodeDom如果你覺得可怕)。 PetaPoco今天早些時候展示了一個類似的例子:prevent DynamicMethod VerificationException - operation could destabilize the runtime

你也可以看看其他序列化引擎的代碼,比如protobuf-net,它有大量的元編程。

如果你不想去相當那麼遠,你可以看看FastMember,它會爲你瘋狂的東西,所以你只需要擔心的對象/成員名稱/值。

+0

是的,我很老實,反思說實話,我知道有很多方法可以用IL編程LowLevel以獲得最佳結果,甚至在運行時創建動態類,但現在我試圖避免這些路徑,因爲它們現在對我來說太困難了。我已經通過使用TryGetvalue刪除Try Catch語句解決了這個問題(儘管我不知道爲什麼要修復性能問題)。我會研究FastMember,但未來的優化問題:)。謝謝 – 2012-07-27 08:04:55

相關問題