今天,一個因為 ORM 的性能問題引發了一場血案,唉。。。
突然想起來幾年前我寫的一個小東西,放上來大家評論一下,有興趣的可以測試一下性能,呵呵。
原理很簡單,利用 Lambda 表達式樹生成一個 Delegate ,然后緩存起來。不多說了,下面上代碼:
using System;
using System.Collections.Generic;
using System.Data;
using System.Diagnostics;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using Lenic.Extensions;
namespace Lenic.Data.Extensions
{
/// <summary>
/// IDataReader 擴展方法集合
/// </summary>
[DebuggerStepThrough]
public static class DataReaderExtensions
{
#region Private Methods
private static readonly Dictionary<Type, Delegate> cache = new Dictionary<Type, Delegate>();
private static readonly object cacheLocker = new object();
#endregion
#region Business Methods
/// <summary>
/// 返回指定字段的值, 並執行 ConvertTo 函數轉換。
/// </summary>
/// <typeparam name="T">返回值類型。</typeparam>
/// <param name="reader">一個實現了 IDataReader 接口的實例對象。</param>
/// <param name="name">要查找的字段的名稱。</param>
/// <returns>轉換完畢的 T 類型的結果。</returns>
public static T Field<T>(this IDataReader reader, string name)
{
return reader[name].ConvertTo<T>(default(T), false);
}
/// <summary>
/// 返回指定字段的值, 並執行 ConvertTo 函數轉換。
/// </summary>
/// <typeparam name="T">返回值類型。</typeparam>
/// <param name="reader">一個實現了 IDataReader 接口的實例對象。</param>
/// <param name="index">要查找的字段的索引。</param>
/// <returns>轉換完畢的 T 類型的結果。</returns>
public static T Field<T>(this IDataReader reader, int index)
{
return reader[index].ConvertTo<T>(default(T), false);
}
/// <summary>
/// 解析當前 IDataReader 類型的實例對象並提取一個 T 類型的列表。
/// </summary>
/// <typeparam name="T">待解析的元素類型, 該類型必須包含一個默認的構造函數。</typeparam>
/// <param name="reader">一個實現了 IDataReader 接口的實例對象。</param>
/// <returns>一個 T 類型的列表。</returns>
public static List<T> ToList<T>(this IDataReader reader) where T : class, new()
{
return Fill<T>(reader, DynamicCreateEntity<T>()).ToList();
}
/// <summary>
/// 解析當前 IDataReader 類型的實例對象並提取一個 T 類型的列表。
/// </summary>
/// <typeparam name="T">待解析的元素類型, 該類型必須包含一個默認的構造函數。</typeparam>
/// <param name="reader">一個實現了 IDataReader 接口的實例對象。</param>
/// <param name="predicate">映射委托。</param>
/// <returns>一個 T 類型的列表。</returns>
public static List<T> ToList<T>(this IDataReader reader, Func<IDataReader, T> predicate)
where T : class, new()
{
return Fill<T>(reader, predicate).ToList();
}
#endregion
#region Private Methods
/// <summary>
/// 創建一個 構造函數 委托。
/// </summary>
/// <typeparam name="T">構造目標類型。</typeparam>
/// <returns>構造完畢的 Func 委托。</returns>
private static Func<IDataReader, T> DynamicCreateEntity<T>() where T : class, new()
{
var type = typeof(T);
if (cache.ContainsKey(type))
return (Func<IDataReader, T>)cache[type];
lock (cacheLocker)
{
if (cache.ContainsKey(type))
return (Func<IDataReader, T>)cache[type];
var result = DynamicCreateEntityLogic<T>();
cache.Add(type, result);
return result;
}
}
/// <summary>
/// 創建一個 構造函數 委托(邏輯實現)。
/// </summary>
/// <typeparam name="T">構造目標類型。</typeparam>
/// <returns>構造完畢的 Func 委托。</returns>
private static Func<IDataReader, T> DynamicCreateEntityLogic<T>() where T : class, new()
{
// Compiles a delegate of the form (IDataReader r) => new T { Prop1 = r.Field<Prop1Type>("Prop1"), ... }
ParameterExpression r = Expression.Parameter(typeof(IDataReader), "r");
// Get Properties of the property can read and write
var props = typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance)
.Where(p => p.CanRead && p.CanWrite)
.ToArray();
// Create property bindings for all writable properties
List<MemberBinding> bindings = new List<MemberBinding>(props.Length);
// Get the binding method
var method = typeof(DataReaderExtensions).GetMethods()
.First(p => p.Name == "Field" &&
p.GetParameters().Length == 2 &&
p.GetParameters()[1].ParameterType == typeof(string));
foreach (PropertyInfo property in (typeof(T).GetProperties()))
{
// Create expression representing r.Field<property.PropertyType>(property.Name)
MethodCallExpression propertyValue = Expression.Call(
method.MakeGenericMethod(property.PropertyType),
r, Expression.Constant(property.Name));
// Assign the property value to property through a member binding
MemberBinding binding = Expression.Bind(property, propertyValue);
bindings.Add(binding);
}
// Create the initializer, which instantiates an instance of T and sets property values
// using the member bindings we just created
Expression initializer = Expression.MemberInit(Expression.New(typeof(T)), bindings);
// Create the lambda expression, which represents the complete delegate (r => initializer)
Expression<Func<IDataReader, T>> lambda = Expression.Lambda<Func<IDataReader, T>>(initializer, r);
return lambda.Compile();
}
/// <summary>
/// 從一個 IDataReader 的實例對象中提取一個 T 類型的列表。
/// </summary>
/// <typeparam name="T">結果列表中的元素類型, 該類型必須包含一個默認的構造函數。</typeparam>
/// <param name="reader">一個實現了 IDataReader 接口的實例對象。</param>
/// <returns>一個 T 類型的列表。</returns>
private static IEnumerable<T> Fill<T>(IDataReader reader, Func<IDataReader, T> predicate) where T : class, new()
{
while (reader.Read())
yield return predicate(reader);
}
#endregion
}
}
上面用到了一個全能轉換方法,代碼如下:
#region Type Convert Extensions
private static string typeIConvertibleFullName = typeof(IConvertible).FullName;
/// <summary>
/// 將當前實例對象類型轉換為 T 類型.
/// </summary>
/// <typeparam name="T">目標類型.</typeparam>
/// <param name="obj">當前實例.</param>
/// <returns>轉換完成的 T 類型的一個實例對象.</returns>
public static T ConvertTo<T>(this object obj)
{
return ConvertTo(obj, default(T));
}
/// <summary>
/// 將當前實例對象類型轉換為 T 類型.
/// </summary>
/// <typeparam name="T">目標類型.</typeparam>
/// <param name="obj">當前實例.</param>
/// <param name="defaultValue">轉換失敗時的返回值.</param>
/// <returns>轉換完成的 T 類型的一個實例對象.</returns>
public static T ConvertTo<T>(this object obj, T defaultValue)
{
if (obj != null)
{
if (obj is T)
return (T)obj;
var sourceType = obj.GetType();
var targetType = typeof(T);
if (targetType.IsEnum)
return (T)Enum.Parse(targetType, obj.ToString(), true);
if (sourceType.GetInterface(typeIConvertibleFullName) != null &&
targetType.GetInterface(typeIConvertibleFullName) != null)
return (T)Convert.ChangeType(obj, targetType);
var converter = TypeDescriptor.GetConverter(obj);
if (converter != null && converter.CanConvertTo(targetType))
return (T)converter.ConvertTo(obj, targetType);
converter = TypeDescriptor.GetConverter(targetType);
if (converter != null && converter.CanConvertFrom(sourceType))
return (T)converter.ConvertFrom(obj);
throw new ApplicationException("convert error.");
}
throw new ArgumentNullException("obj");
}
/// <summary>
/// 將當前實例對象類型轉換為 T 類型.
/// </summary>
/// <typeparam name="T">目標類型.</typeparam>
/// <param name="obj">當前實例.</param>
/// <param name="defaultValue">轉換失敗時的返回值.</param>
/// <param name="ignoreException">如果設置為 <c>true</c> 表示忽略異常信息, 直接返回缺省值.</param>
/// <returns>轉換完成的 T 類型的一個實例對象.</returns>
public static T ConvertTo<T>(this object obj, T defaultValue, bool ignoreException)
{
if (ignoreException)
{
try
{
return obj.ConvertTo<T>(defaultValue);
}
catch
{
return defaultValue;
}
}
return obj.ConvertTo<T>(defaultValue);
}
#endregion
再次歡迎大家品鑒。
