2009-11-10 133 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