using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
using System.Reflection;
using System.Linq.Expressions;
using System.Threading;
public static class IDataReaderHelper
{
#region 核心代码
/// <summary>
/// 将IDataReader 转换为指定的类型,动态预编译,调用时注意不要重复调用
/// 性能上要优于反射,对于10*500*10000条数据的反序列化,
/// lambda 表达式 的性能是 反射的 10倍左右(10*500平均值)
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="reader"></param>
/// <returns></returns>
public static Func<IDataReader, T> GetDeserializer<T>(IDataReader reader)
{
ParameterExpression paramReader = Expression.Parameter(typeof(IDataReader), "reader");
//在内部构建 DbFieldReader 对象
var dbReaderExpr = Expression.New(typeof(DbFieldReader).GetConstructor(new Type[] { typeof(IDataReader) }), new Expression[] { paramReader });
Expression CreateDbFieldReader = Expression.Lambda<Func<IDataReader, DbFieldReader>>(dbReaderExpr, paramReader);
ParameterExpression paramInner = Expression.Parameter(typeof(FieldReader), "dbreader");
MethodInfo IsDBNull = typeof(FieldReader).GetMethod("IsDBNull", BindingFlags.Public | BindingFlags.Instance);
var columnList = Enumerable.Range(0, reader.FieldCount).Select(index =>
{
Type NonNullTpype = TypeHelper.GetNonNullableType(reader.GetFieldType(index));
return new
{
Name = reader.GetName(index),
Index = index,
Type = NonNullTpype,
Reader = Expression.Condition(Expression.Call(paramInner, IsDBNull, Expression.Constant(index)),
Expression.Convert(Expression.Constant(TypeHelper.GetDefault(NonNullTpype)), NonNullTpype),
Expression.Call(paramInner, FieldReader.GetReaderMethod(NonNullTpype), new[] { Expression.Constant(index) }))
};
});
ConstructorInfo[] constructor = typeof(T).GetConstructors();
Expression lambdaBody;
IEnumerable<ColumnInfo> bindList = typeof(T).GetProperties().Select(obj =>
{
Type NonNullType = TypeHelper.GetNonNullableType(obj.PropertyType);
var columnInfo = columnList.FirstOrDefault(col => col.Type == NonNullType && string.Equals(col.Name, obj.Name, StringComparison.CurrentCultureIgnoreCase));
MemberInfo member = obj as MemberInfo;
if (columnInfo == null)
{
return new ColumnInfo { Expression = Expression.Convert(Expression.Constant(TypeHelper.GetDefault(NonNullType)), obj.PropertyType), Info = member };
}
//binding 类型必须一致
Expression expr;
if (obj.PropertyType != NonNullType)
{
expr = Expression.Convert(columnInfo.Reader, obj.PropertyType);
}
else
{
expr = columnInfo.Reader;
}
return new ColumnInfo
{
Expression = expr,
Info = member
};
});
if (constructor.Any(ctor => ctor.GetParameters().Length == 0))
{
lambdaBody = Expression.MemberInit(Expression.New(typeof(T)), bindList.Select(obj => Expression.Bind(obj.Info, obj.Expression) as MemberBinding));
}
else
{
ConstructorInfo ctor = constructor.FirstOrDefault(obj => obj.GetParameters().Length == bindList.Count());
if (ctor == null) throw new ArgumentException(" 不可实例化该对象 ");
lambdaBody = Expression.New(ctor, bindList.Select(obj => obj.Expression).ToArray());
}
LambdaExpression subLambda = Expression.Lambda<Func<FieldReader, T>>(lambdaBody, paramInner);
Expression invoke = Expression.Invoke(subLambda, Expression.Invoke(CreateDbFieldReader, paramReader));
Func<IDataReader, T> projector = Expression.Lambda<Func<IDataReader, T>>(invoke, paramReader).Compile();
return projector;
}
internal class ColumnInfo
{
public Expression Expression { get; set; }
public MemberInfo Info { get; set; }
}
public abstract class FieldReader
{
TypeCode[] typeCodes;
public FieldReader()
{
}
protected void Init()
{
this.typeCodes = new TypeCode[this.FieldCount];
}
public abstract int FieldCount { get; }
public abstract Type GetFieldType(int ordinal);
public abstract bool IsDBNull(int ordinal);
protected abstract T GetValue<T>(int ordinal);
protected abstract Byte GetByte(int ordinal);
protected abstract Char GetChar(int ordinal);
protected abstract DateTime GetDateTime(int ordinal);
protected abstract Decimal GetDecimal(int ordinal);
protected abstract Double GetDouble(int ordinal);
protected abstract Single GetSingle(int ordinal);
protected abstract Guid GetGuid(int ordinal);
protected abstract Int16 GetInt16(int ordinal);
protected abstract Int32 GetInt32(int ordinal);
protected abstract Int64 GetInt64(int ordinal);
protected abstract String GetString(int ordinal);
public T ReadValue<T>(int ordinal)
{
if (this.IsDBNull(ordinal))
{
return default(T);
}
return this.GetValue<T>(ordinal);
}
public T? ReadNullableValue<T>(int ordinal) where T : struct
{
if (this.IsDBNull(ordinal))
{
return default(T?);
}
return this.GetValue<T>(ordinal);
}
public Byte ReadByte(int ordinal)
{
if (this.IsDBNull(ordinal))
{
return default(Byte);
}
while (true)
{
switch (typeCodes[ordinal])
{
case TypeCode.Empty:
typeCodes[ordinal] = GetTypeCode(ordinal);
continue;
case TypeCode.Byte:
return this.GetByte(ordinal);
case TypeCode.Int16:
return (Byte)this.GetInt16(ordinal);
case TypeCode.Int32:
return (Byte)this.GetInt32(ordinal);
case TypeCode.Int64:
return (Byte)this.GetInt64(ordinal);
case TypeCode.Double:
return (Byte)this.GetDouble(ordinal);
case TypeCode.Single:
return (Byte)this.GetSingle(ordinal);
case TypeCode.Decimal:
return (Byte)this.GetDecimal(ordinal);
default:
return this.GetValue<Byte>(ordinal);
}
}
}
public Byte? ReadNullableByte(int ordinal)
{
if (this.IsDBNull(ordinal))
{
return default(Byte?);
}
while (true)
{
switch (typeCodes[ordinal])
{
case TypeCode.Empty:
typeCodes[ordinal] = GetTypeCode(ordinal);
continue;
case TypeCode.Byte:
return this.GetByte(ordinal);
case TypeCode.Int16:
return (Byte)this.GetInt16(ordinal);
case TypeCode.Int32:
return (Byte)this.GetInt32(ordinal);
case TypeCode.Int64:
return (Byte)this.GetInt64(ordinal);
case TypeCode.Double:
return (Byte)this.GetDouble(ordinal);
case TypeCode.Single:
return (Byte)this.GetSingle(ordinal);
case TypeCode.Decimal:
return (Byte)this.GetDecimal(ordinal);
default:
return (Byte)this.GetValue<Byte>(ordinal);
}
}
}
public Char ReadChar(int ordinal)
{
if (this.IsDBNull(ordinal))
{
return default(Char);
}
while (true)
{
switch (typeCodes[ordinal])
{
case TypeCode.Empty:
typeCodes[ordinal] = GetTypeCode(ordinal);
continue;
case TypeCode.Byte:
return (Char)this.GetByte(ordinal);
case TypeCode.Int16:
return (Char)this.GetInt16(ordinal);
case TypeCode.Int32:
return (Char)this.GetInt32(ordinal);
case TypeCode.Int64:
return (Char)this.GetInt64(ordinal);
case TypeCode.Double:
return (Char)this.GetDouble(ordinal);
case TypeCode.Single:
return (Char)this.GetSingle(ordinal);
case TypeCode.Decimal:
return (Char)this.GetDecimal(ordinal);
default:
return this.GetValue<Char>(ordinal);
}
}
}
public Char? ReadNullableChar(int ordinal)
{
if (this.IsDBNull(ordinal))
{
return default(Char?);
}
while (true)
{
switch (typeCodes[ordinal])
{
case TypeCode.Empty:
typeCodes[ordinal] = GetTypeCode(ordinal);
continue;
case TypeCode.Byte:
return (Char)this.GetByte(ordinal);
case TypeCode.Int16:
return (Char)this.GetInt16(ordinal);
case TypeCode.Int32:
return (Char)this.GetInt32(ordinal);
case TypeCode.Int64:
return (Char)this.GetInt64(ordinal);
case TypeCode.Double:
return (Char)this.GetDouble(ordinal);
case TypeCode.Single:
return (Char)this.GetSingle(ordinal);
case TypeCode.Decimal:
return (Char)this.GetDecimal(ordinal);
default:
return this.GetValue<Char>(ordinal);
}
}
}
public DateTime ReadDateTime(int ordinal)
{
if (this.IsDBNull(ordinal))
{
return default(DateTime);
}
while (true)
{
switch (typeCodes[ordinal])
{
case TypeCode.Empty:
typeCodes[ordinal] = GetTypeCode(ordinal);
continue;
case TypeCode.DateTime:
return this.GetDateTime(ordinal);
default:
return this.GetValue<DateTime>(ordinal);
}
}
}
public DateTime? ReadNullableDateTime(int ordinal)
{
if (this.IsDBNull(ordinal))
{
return default(DateTime?);
}
while (true)
{
switch (typeCodes[ordinal])
{
case TypeCode.Empty:
typeCodes[ordinal] = GetTypeCode(ordinal);
continue;
case TypeCode.DateTime:
return this.GetDateTime(ordinal);
default:
return this.GetValue<DateTime>(ordinal);
}
}
}
public Decimal ReadDecimal(int ordinal)
{
if (this.IsDBNull(ordinal))
{
return default(Decimal);
}
while (true)
{
switch (typeCodes[ordinal])
{
case TypeCode.Empty:
typeCodes[ordinal] = GetTypeCode(ordinal);
continue;
case TypeCode.Byte:
return (Decimal)this.GetByte(ordinal);
case TypeCode.Int16:
return (Decimal)this.GetInt16(ordinal);
case TypeCode.Int32:
return (Decimal)this.GetInt32(ordinal);
case TypeCode.Int64:
return (Decimal)this.GetInt64(ordinal);
case TypeCode.Double:
return (Decimal)this.GetDouble(ordinal);
case TypeCode.Single:
return (Decimal)this.GetSingle(ordinal);
case TypeCode.Decimal:
return this.GetDecimal(ordinal);
default:
return this.GetValue<Decimal>(ordinal);
}
}
}
public Decimal? ReadNullableDecimal(int ordinal)
{
if (this.IsDBNull(ordinal))
{
return default(Decimal?);
}
while (true)
{
switch (typeCodes[ordinal])
{
case TypeCode.Empty:
typeCodes[ordinal] = GetTypeCode(ordinal);
continue;
case TypeCode.Byte:
return (Decimal)this.GetByte(ordinal);
case TypeCode.Int16:
return (Decimal)this.GetInt16(ordinal);
case TypeCode.Int32:
return (Decimal)this.GetInt32(ordinal);
case TypeCode.Int64:
return (Decimal)this.GetInt64(ordinal);
case TypeCode.Double:
return (Decimal)this.GetDouble(ordinal);
case TypeCode.Single:
return (Decimal)this.GetSingle(ordinal);
case TypeCode.Decimal:
return this.GetDecimal(ordinal);
default:
return this.GetValue<Decimal>(ordinal);
}
}
}
public Double ReadDouble(int ordinal)
{
if (this.IsDBNull(ordinal))
{
return default(Double);
}
while (true)
{
switch (typeCodes[ordinal])
{
case TypeCode.Empty:
typeCodes[ordinal] = GetTypeCode(ordinal);
continue;
case TypeCode.Byte:
return (Double)this.GetByte(ordinal);
case TypeCode.Int16:
return (Double)this.GetInt16(ordinal);
case TypeCode.Int32:
return (Double)this.GetInt32(ordinal);
case TypeCode.Int64:
return (Double)this.GetInt64(ordinal);
case TypeCode.Double:
return this.GetDouble(ordinal);
case TypeCode.Single:
return (Double)this.GetSingle(ordinal);
case TypeCode.Decimal:
return (Double)this.GetDecimal(ordinal);
default:
return this.GetValue<Double>(ordinal);
}
}
}
public Double? ReadNullableDouble(int ordinal)
{
if (this.IsDBNull(ordinal))
{
return default(Double?);
}
while (true)
{
switch (typeCodes[ordinal])
{
case TypeCode.Empty:
typeCodes[ordinal] = GetTypeCode(ordinal);
continue;
case TypeCode.Byte:
return (Double)this.GetByte(ordinal);
case TypeCode.Int16:
return (Double)this.GetInt16(ordinal);
case TypeCode.Int32:
return (Double)this.GetInt32(ordinal);
case TypeCode.Int64:
return (Double)this.GetInt64(ordinal);
case TypeCode.Double:
return this.GetDouble(ordinal);
case TypeCode.Single:
return (Double)this.GetSingle(ordinal);
case TypeCode.Decimal:
return (Double)this.GetDecimal(ordinal);
default:
return this.GetValue<Double>(ordinal);
}
}
}
public Single ReadSingle(int ordinal)
{
if (this.IsDBNull(ordinal))
{
return default(Single);
}
while (true)
{
switch (typeCodes[ordinal])
{
case TypeCode.Empty:
typeCodes[ordinal] = GetTypeCode(ordinal);
continue;
case TypeCode.Byte:
return (Single)this.GetByte(ordinal);
case TypeCode.Int16:
return (Single)this.GetInt16(ordinal);
case TypeCode.Int32:
return (Single)this.GetInt32(ordinal);
case TypeCode.Int64:
return (Single)this.GetInt64(ordinal);
case TypeCode.Double:
return (Single)this.GetDouble(ordinal);
case TypeCode.Single:
return this.GetSingle(ordinal);
case TypeCode.Decimal:
return (Single)this.GetDecimal(ordinal);
default:
return this.GetValue<Single>(ordinal);
}
}
}
public Single? ReadNullableSingle(int ordinal)
{
if (this.IsDBNull(ordinal))
{
return default(Single?);
}
while (true)
{
switch (typeCodes[ordinal])
{
case TypeCode.Empty:
typeCodes[ordinal] = GetTypeCode(ordinal);
continue;
case TypeCode.Byte:
return (Single)this.GetByte(ordinal);
case TypeCode.Int16:
return (Single)this.GetInt16(ordinal);
case TypeCode.Int32:
return (Single)this.GetInt32(ordinal);
case TypeCode.Int64:
return (Single)this.GetInt64(ordinal);
case TypeCode.Double:
return (Single)this.GetDouble(ordinal);
case TypeCode.Single:
return this.GetSingle(ordinal);
case TypeCode.Decimal:
return (Single)this.GetDecimal(ordinal);
default:
return this.GetValue<Single>(ordinal);
}
}
}
public Guid ReadGuid(int ordinal)
{
if (this.IsDBNull(ordinal))
{
return default(Guid);
}
while (true)
{
switch (typeCodes[ordinal])
{
case TypeCode.Empty:
typeCodes[ordinal] = GetTypeCode(ordinal);
continue;
case tcGuid:
return this.GetGuid(ordinal);
default:
return this.GetValue<Guid>(ordinal);
}
}
}
public Guid? ReadNullableGuid(int ordinal)
{
if (this.IsDBNull(ordinal))
{
return default(Guid?);
}
while (true)
{
switch (typeCodes[ordinal])
{
case TypeCode.Empty:
typeCodes[ordinal] = GetTypeCode(ordinal);
continue;
case tcGuid:
return this.GetGuid(ordinal);
default:
return this.GetValue<Guid>(ordinal);
}
}
}
public Int16 ReadInt16(int ordinal)
{
if (this.IsDBNull(ordinal))
{
return default(Int16);
}
while (true)
{
switch (typeCodes[ordinal])
{
case TypeCode.Empty:
typeCodes[ordinal] = GetTypeCode(ordinal);
continue;
case TypeCode.Byte:
return (Int16)this.GetByte(ordinal);
case TypeCode.Int16:
return (Int16)this.GetInt16(ordinal);
case TypeCode.Int32:
return (Int16)this.GetInt32(ordinal);
case TypeCode.Int64:
return (Int16)this.GetInt64(ordinal);
case TypeCode.Double:
return (Int16)this.GetDouble(ordinal);
case TypeCode.Single:
return (Int16)this.GetSingle(ordinal);
case TypeCode.Decimal:
return (Int16)this.GetDecimal(ordinal);
default:
return this.GetValue<Int16>(ordinal);
}
}
}
public Int16? ReadNullableInt16(int ordinal)
{
if (this.IsDBNull(ordinal))
{
return default(Int16?);
}
while (true)
{
switch (typeCodes[ordinal])
{
case TypeCode.Empty:
typeCodes[ordinal] = GetTypeCode(ordinal);
continue;
case TypeCode.Byte:
return (Int16)this.GetByte(ordinal);
case TypeCode.Int16:
return (Int16)this.GetInt16(ordinal);
case TypeCode.Int32:
return (Int16)this.GetInt32(ordinal);
case TypeCode.Int64:
return (Int16)this.GetInt64(ordinal);
case TypeCode.Double:
return (Int16)this.GetDouble(ordinal);
case TypeCode.Single:
return (Int16)this.GetSingle(ordinal);
case TypeCode.Decimal:
return (Int16)this.GetDecimal(ordinal);
default:
return this.GetValue<Int16>(ordinal);
}
}
}
public Int32 ReadInt32(int ordinal)
{
if (this.IsDBNull(ordinal))
{
return default(Int32);
}
while (true)
{
switch (typeCodes[ordinal])
{
case TypeCode.Empty:
typeCodes[ordinal] = GetTypeCode(ordinal);
continue;
case TypeCode.Byte:
return (Int32)this.GetByte(ordinal);
case TypeCode.Int16:
return (Int32)this.GetInt16(ordinal);
case TypeCode.Int32:
return (Int32)this.GetInt32(ordinal);
case TypeCode.Int64:
return (Int32)this.GetInt64(ordinal);
case TypeCode.Double:
return (Int32)this.GetDouble(ordinal);
case TypeCode.Single:
return (Int32)this.GetSingle(ordinal);
case TypeCode.Decimal:
return (Int32)this.GetDecimal(ordinal);
default:
return this.GetValue<Int32>(ordinal);
}
}
}
public Int32? ReadNullableInt32(int ordinal)
{
if (this.IsDBNull(ordinal))
{
return default(Int32?);
}
while (true)
{
switch (typeCodes[ordinal])
{
case TypeCode.Empty:
typeCodes[ordinal] = GetTypeCode(ordinal);
continue;
case TypeCode.Byte:
return (Int32)this.GetByte(ordinal);
case TypeCode.Int16:
return (Int32)this.GetInt16(ordinal);
case TypeCode.Int32:
return (Int32)this.GetInt32(ordinal);
case TypeCode.Int64:
return (Int32)this.GetInt64(ordinal);
case TypeCode.Double:
return (Int32)this.GetDouble(ordinal);
case TypeCode.Single:
return (Int32)this.GetSingle(ordinal);
case TypeCode.Decimal:
return (Int32)this.GetDecimal(ordinal);
default:
return this.GetValue<Int32>(ordinal);
}
}
}
public Int64 ReadInt64(int ordinal)
{
if (this.IsDBNull(ordinal))
{
return default(Int64);
}
while (true)
{
switch (typeCodes[ordinal])
{
case TypeCode.Empty:
typeCodes[ordinal] = GetTypeCode(ordinal);
continue;
case TypeCode.Byte:
return (Int64)this.GetByte(ordinal);
case TypeCode.Int16:
return (Int64)this.GetInt16(ordinal);
case TypeCode.Int32:
return (Int64)this.GetInt32(ordinal);
case TypeCode.Int64:
return (Int64)this.GetInt64(ordinal);
case TypeCode.Double:
return (Int64)this.GetDouble(ordinal);
case TypeCode.Single:
return (Int64)this.GetSingle(ordinal);
case TypeCode.Decimal:
return (Int64)this.GetDecimal(ordinal);
default:
return this.GetValue<Int64>(ordinal);
}
}
}
public Int64? ReadNullableInt64(int ordinal)
{
if (this.IsDBNull(ordinal))
{
return default(Int64?);
}
while (true)
{
switch (typeCodes[ordinal])
{
case TypeCode.Empty:
typeCodes[ordinal] = GetTypeCode(ordinal);
continue;
case TypeCode.Byte:
return (Int64)this.GetByte(ordinal);
case TypeCode.Int16:
return (Int64)this.GetInt16(ordinal);
case TypeCode.Int32:
return (Int64)this.GetInt32(ordinal);
case TypeCode.Int64:
return (Int64)this.GetInt64(ordinal);
case TypeCode.Double:
return (Int64)this.GetDouble(ordinal);
case TypeCode.Single:
return (Int64)this.GetSingle(ordinal);
case TypeCode.Decimal:
return (Int64)this.GetDecimal(ordinal);
default:
return this.GetValue<Int64>(ordinal);
}
}
}
public String ReadString(int ordinal)
{
if (this.IsDBNull(ordinal))
{
return default(String);
}
while (true)
{
switch (typeCodes[ordinal])
{
case TypeCode.Empty:
typeCodes[ordinal] = Type.GetTypeCode(this.GetFieldType(ordinal));
continue;
case TypeCode.Byte:
return this.GetByte(ordinal).ToString();
case TypeCode.Int16:
return this.GetInt16(ordinal).ToString();
case TypeCode.Int32:
return this.GetInt32(ordinal).ToString();
case TypeCode.Int64:
return this.GetInt64(ordinal).ToString();
case TypeCode.Double:
return this.GetDouble(ordinal).ToString();
case TypeCode.Single:
return this.GetSingle(ordinal).ToString();
case TypeCode.Decimal:
return this.GetDecimal(ordinal).ToString();
case TypeCode.DateTime:
return this.GetDateTime(ordinal).ToString();
case tcGuid:
return this.GetGuid(ordinal).ToString();
case TypeCode.String:
return this.GetString(ordinal);
default:
return this.GetValue<String>(ordinal);
}
}
}
public Byte[] ReadByteArray(int ordinal)
{
if (this.IsDBNull(ordinal))
{
return default(Byte[]);
}
while (true)
{
switch (typeCodes[ordinal])
{
case TypeCode.Empty:
typeCodes[ordinal] = GetTypeCode(ordinal);
continue;
case TypeCode.Byte:
return new Byte[] { this.GetByte(ordinal) };
default:
return this.GetValue<Byte[]>(ordinal);
}
}
}
public Char[] ReadCharArray(int ordinal)
{
if (this.IsDBNull(ordinal))
{
return default(Char[]);
}
while (true)
{
switch (typeCodes[ordinal])
{
case TypeCode.Empty:
typeCodes[ordinal] = GetTypeCode(ordinal);
continue;
case TypeCode.Char:
return new Char[] { this.GetChar(ordinal) };
default:
return this.GetValue<Char[]>(ordinal);
}
}
}
private const TypeCode tcGuid = (TypeCode)20;
private const TypeCode tcByteArray = (TypeCode)21;
private const TypeCode tcCharArray = (TypeCode)22;
private TypeCode GetTypeCode(int ordinal)
{
Type type = this.GetFieldType(ordinal);
TypeCode tc = Type.GetTypeCode(type);
if (tc == TypeCode.Object)
{
if (type == typeof(Guid))
tc = tcGuid;
else if (type == typeof(Byte[]))
tc = tcByteArray;
else if (type == typeof(Char[]))
tc = tcCharArray;
}
return tc;
}
protected static bool IsNullableType(Type type)
{
return TypeHelper.IsNullableType(type);
//return type != null && type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>);
}
protected static Type GetNonNullableType(Type type)
{
return TypeHelper.GetNonNullableType(type);
//if (IsNullableType(type))
//{
// return type.GetGenericArguments()[0];
//}
//return type;
}
public static MethodInfo GetReaderMethod(Type type)
{
if (_readerMethods == null)
{
var meths = typeof(FieldReader).GetMethods(BindingFlags.Public | BindingFlags.Instance).Where(m => m.Name.StartsWith("Read")).ToList();
_readerMethods = meths.ToDictionary(m => m.ReturnType);
_miReadValue = meths.Single(m => m.Name == "ReadValue");
_miReadNullableValue = meths.Single(m => m.Name == "ReadNullableValue");
}
MethodInfo mi;
_readerMethods.TryGetValue(type, out mi);
if (mi == null)
{
if (IsNullableType(type))
{
mi = _miReadNullableValue.MakeGenericMethod(GetNonNullableType(type));
}
else
{
//如果没有该类型的方法,生成泛型方法
mi = _miReadValue.MakeGenericMethod(type);
}
}
return mi;
}
static Dictionary<Type, MethodInfo> _readerMethods;
static MethodInfo _miReadValue;
static MethodInfo _miReadNullableValue;
}
public class DbFieldReader : FieldReader
{
IDataReader reader;
public DbFieldReader(IDataReader reader)
{
this.reader = reader;
this.Init();
}
public override int FieldCount
{
get { return this.reader.FieldCount; }
}
public override Type GetFieldType(int ordinal)
{
return this.reader.GetFieldType(ordinal);
}
public override bool IsDBNull(int ordinal)
{
return this.reader.IsDBNull(ordinal);
}
protected override T GetValue<T>(int ordinal)
{
return (T)Convert(this.reader.GetValue(ordinal), typeof(T));
}
protected override Byte GetByte(int ordinal)
{
return this.reader.GetByte(ordinal);
}
protected override Char GetChar(int ordinal)
{
return this.reader.GetChar(ordinal);
}
protected override DateTime GetDateTime(int ordinal)
{
return this.reader.GetDateTime(ordinal);
}
protected override Decimal GetDecimal(int ordinal)
{
return this.reader.GetDecimal(ordinal);
}
protected override Double GetDouble(int ordinal)
{
return this.reader.GetDouble(ordinal);
}
protected override Single GetSingle(int ordinal)
{
return this.reader.GetFloat(ordinal);
}
protected override Guid GetGuid(int ordinal)
{
return this.reader.GetGuid(ordinal);
}
protected override Int16 GetInt16(int ordinal)
{
return this.reader.GetInt16(ordinal);
}
protected override Int32 GetInt32(int ordinal)
{
return this.reader.GetInt32(ordinal);
}
protected override Int64 GetInt64(int ordinal)
{
return this.reader.GetInt64(ordinal);
}
protected override String GetString(int ordinal)
{
return this.reader.GetString(ordinal);
}
private object GetDefault(Type type)
{
bool isNullable = !type.IsValueType || IsNullableType(type);
if (!isNullable)
return Activator.CreateInstance(type);
return null;
}
private object Convert(object value, Type type)
{
if (value == null)
{
return GetDefault(type);
}
type = GetNonNullableType(type);
Type vtype = value.GetType();
if (type != vtype)
{
if (type.IsEnum)
{
if (vtype == typeof(string))
{
return Enum.Parse(type, (string)value);
}
else
{
Type utype = Enum.GetUnderlyingType(type);
if (utype != vtype)
{
value = System.Convert.ChangeType(value, utype);
}
return Enum.ToObject(type, value);
}
}
return System.Convert.ChangeType(value, type);
}
return value;
}
}
internal static class TypeHelper
{
public static bool IsNullableType(Type type)
{
return type != null && type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>);
}
public static Type GetNonNullableType(Type type)
{
if (IsNullableType(type))
{
return type.GetGenericArguments()[0];
}
return type;
}
public static object GetDefault(Type type)
{
bool isNullable = !type.IsValueType || IsNullableType(type);
if (!isNullable)
return Activator.CreateInstance(type);
return null;
}
}
#endregion
#region 扩展方法部分
/// <summary>
/// DataSet 扩展方法,直接转换为指定的类
/// 支持匿名对象,需动态调用
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="ds"></param>
/// <returns></returns>
public static IEnumerable<T> ToEnumerable<T>(this DataSet ds)
{
if (ds == null || ds.Tables.Count == 0 || ds.Tables[0].Rows.Count == 0) return new List<T>();
using (IDataReader reader = ds.Tables[0].CreateDataReader())
{
return ReadData<T>(reader).ToList();
}
}
/// <summary>
/// dataset 转换为自定义的匿名类型
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="ds"></param>
/// <param name="model"></param>
/// <returns></returns>
public static IEnumerable<T> ToAnonymousModel<T>(this DataSet ds, T model)
{
if (ds == null || ds.Tables.Count == 0 || ds.Tables[0].Rows.Count == 0) return new List<T>();
MethodInfo mi = typeof(IDataReaderHelper).GetMethod("ToEnumerable", BindingFlags.Static | BindingFlags.Public).MakeGenericMethod(typeof(T));
return mi.Invoke(null, new[] { ds }) as IEnumerable<T>;
}
private static IEnumerable<T> ReadData<T>(IDataReader reader)
{
try
{
var fn = IDataReaderHelper.GetDeserializer<T>(reader);
while (reader.Read())
{
yield return fn(reader);
}
}
finally
{
reader.Dispose();
}
}
#endregion
}
从IDataReaderHelper中读取数据实体
最新推荐文章于 2022-09-06 22:44:55 发布