2009-11-10 182 views
0

我有一種方法,實質上是將一個數據錶轉換爲我稱之爲「包」的對象列表。這段代碼每次會話都會被調用很多次,其中很多會話會同時運行,有時會有數千行。正因爲如此,我需要它儘可能快。我有一個包含DataColumn屬性映射的XML文件。優化的主要方法是ConvertRowToBag - 傳入的類型參數是從BagBase派生的類型。該代碼如何優化?

這是一個很長的代碼,但任何提示將不勝感激。

public class BagBase 
{ 
    /// <summary> 
    /// Dictionary of properties and names 
    /// </summary> 
    private static Dictionary<string, PropertyInfo> propertyDictionary = new Dictionary<string, PropertyInfo>(); 

    /// <summary> 
    /// Table of column/property mappings 
    /// </summary> 
    private static DataTable mappings = new DataTable("Mappings"); 

    /// <summary> 
    /// Returns true if the map exists 
    /// </summary> 
    /// <param name="columnName"></param> 
    /// <param name="type"></param> 
    /// <returns></returns> 
    private static bool MappingExists(string columnName, Type type) 
    { 
     DataRow [] rows = BagBase.mappings.Select(String.Format("Type = '{0}' and ColumnName = '{1}'", type.Name, columnName)); 
     return (rows != null && rows.Length > 0); 
    } 

    /// <summary> 
    /// Converts the table to bags. 
    /// </summary> 
    /// <param name="table">The table.</param> 
    /// <param name="outputType">Type of the output.</param> 
    /// <returns></returns> 
    protected static List<BagBase> ConvertTableToBags(DataTable table, Type outputType) 
    { 
     Trace.TraceInformation(String.Format("ConvertTableToBags : table={0} Type={1}", table.TableName, outputType.Name)); 

     // Create an empty list 
     List<BagBase> result = new List<BagBase>(); 

     // Iterate through the rows 
     foreach (DataRow row in table.Rows) 
     { 
      // Add to the list 
      result.Add(ConvertRowToBag(outputType, row)); 
     } 

     Trace.TraceInformation("ConvertTableToBags Finished."); 

     return result; 
    } 

    /// <summary> 
    /// Converts the row to bag. 
    /// </summary> 
    /// <param name="outputType">Type of the output.</param> 
    /// <param name="row">The row.</param> 
    /// <returns></returns> 
    protected static BagBase ConvertRowToBag(Type outputType, DataRow row) 
    { 
     // Create an instance of the child class and store in the base 
     BagBase bag = Activator.CreateInstance(outputType) as BagBase; 

     // Iterate through the columns 
     foreach (DataColumn column in row.Table.Columns) 
     { 
      // If this column has been mapped 
      if (BagBase.MappingExists(column.ColumnName, outputType)) 
      { 
       PropertyInfo property; 

       string columnProperty = String.Format("{0}={1}", column.ColumnName, outputType.Name); 

       // Get the property as defined in the map 
       if (!propertyDictionary.ContainsKey(columnProperty)) 
       { 
        // Get the property 
        property = outputType.GetProperty(BagBase.GetColumnMapping(column.ColumnName, outputType)); 

        // Add the property to the dictionary 
        propertyDictionary.Add(columnProperty, property); 
       } 
       else 
       { 
        property = propertyDictionary[columnProperty]; 
       } 

       if (property != null) 
       { 
        if (!row.IsNull(column)) 
        { 
         // Set the value to the in the table 
         if (property.PropertyType.BaseType != null && property.PropertyType.BaseType == typeof(Enum)) 
         { 
          if (column.DataType != typeof(String)) 
          { 
           property.SetValue(bag, Enum.ToObject(property.PropertyType, row[column]), null); 
          } 
          else 
          { 
           property.SetValue(bag, Enum.ToObject(property.PropertyType, Convert.ToChar(row[column])), null); 
          } 
         } 
         else if (property.PropertyType == typeof(DateTime?)) 
         { 
          property.SetValue(bag, (DateTime?)row[column], null); 
         } 
         else 
         { 
          property.SetValue(bag, Convert.ChangeType(row[column], property.PropertyType), null); 
         } 
        } 
        else // No nulls 
        { 
         if (column.DataType == typeof(String)) 
         { 
          property.SetValue(bag, String.Empty, null); 
         } 
        } 

        // Generate the unique class.property name 
        string propertyKey = String.Format("{0}.{1}", outputType.Name, property.Name); 
        if (!columnCaptions.ContainsKey(propertyKey)) 
        { 
         // Add to the caption map 
         columnCaptions.Add(propertyKey, column.Caption); 
        } 
       } 
      } 
      else 
      { 
       // If this column isn't mapped, add it to Other information 
       if (bag.OtherInformation == null) 
       { 
        bag.OtherInformation = new Dictionary<string, string>(); 
       } 

       bag.OtherInformation.Add(column.ColumnName, !row.IsNull(column) ? row[column].ToString() : String.Empty); 
      } 
     } 

     return bag; 
    } 
} 
+2

分析應該確實揭示任何瓶頸,否則發佈在refactormycode.com可以給你更多的見解。 – Mez 2009-11-10 19:22:39

+0

感謝您的鏈接 - 這是我第一次聽說該網站。 – 2009-11-10 19:35:41

+0

refactormycode因維護而關閉 – TankorSmash 2014-12-03 17:57:16

回答

5

使用分析器。我們無法知道代碼中實際需要的最多時間。

試圖逐行優化並沒有什麼用處,許多人似乎都不知道這一點。計算機總是等待資源,有時候是CPU或磁盤IO,並且通常是用戶。爲了使任何代碼更快,使用探查器找到瓶頸並努力提高代碼速度。

+4

只需在此網站上說「使用探查器」即可爲此類問題贏得如此多的聲譽,因爲它總是*正確的答案。再有10分。 – 2009-11-10 18:44:43

+1

+1「使用探查器」是正確的,但不是直接有用的答案。 – 2009-11-10 18:53:40

+0

+1,我認爲這很有幫助。很多人顯然沒有意識到這一點。 – erikkallen 2009-11-10 19:15:21

2

除了「使用探查器」的一般建議之外,可能沒有一個瓶頸,但是一系列緩慢的調用或者過程的結構都會產生不必要的迭代。一目瞭然:

  • Select against datatable通常不是很高效。
  • 反射帶來很多開銷,它看起來像你依賴它,但如果你可以限制它的範圍,你可能會獲得更好的整體性能。
+0

這聽起來像你實際上閱讀代碼!感謝您的建議...... :) – 2009-11-10 19:44:12