Emit绑定实体类型如何判断可空类型Nullable?

事理 2012-08-30 03:12:58
使用下面的方法,但是无法自动绑定可空类型,那位有做过的大侠提示一下,项目有点急人,ILGenerator现在没空研究哦。

internal class DynamicBuilder<T>
{
private static IDictionary<Type, Type> types = new Dictionary<Type, Type>();

private static readonly MethodInfo getValueMethod =
typeof(IDataRecord).GetMethod("get_Item", new Type[] { typeof(int) });

private static readonly MethodInfo isDBNullMethod =
typeof(IDataRecord).GetMethod("IsDBNull", new Type[] { typeof(int) });

private delegate T Load(IDataRecord dataRecord);

private Load handler;

private DynamicBuilder() { }

static DynamicBuilder()
{
types.Add(typeof(bool), typeof(Nullable<bool>));
types.Add(typeof(byte), typeof(Nullable<byte>));
types.Add(typeof(DateTime), typeof(Nullable<DateTime>));
types.Add(typeof(decimal), typeof(Nullable<decimal>));
types.Add(typeof(double), typeof(Nullable<double>));
types.Add(typeof(float), typeof(Nullable<float>));
types.Add(typeof(Guid), typeof(Nullable<Guid>));
types.Add(typeof(Int16), typeof(Nullable<Int16>));
types.Add(typeof(Int32), typeof(Nullable<Int32>));
types.Add(typeof(Int64), typeof(Nullable<Int64>));
}

public T Build(IDataRecord dataRecord)
{
return handler(dataRecord);
}

public static DynamicBuilder<T> CreateBuilder(IDataRecord dataRecord)
{
DynamicBuilder<T> dynamicBuilder = new DynamicBuilder<T>();

DynamicMethod method = new DynamicMethod("DynamicCreate", typeof(T),
new Type[] { typeof(IDataRecord) }, typeof(T), true);
ILGenerator generator = method.GetILGenerator();

LocalBuilder result = generator.DeclareLocal(typeof(T));
generator.Emit(OpCodes.Newobj, typeof(T).GetConstructor(Type.EmptyTypes));
generator.Emit(OpCodes.Stloc, result);

for (int i = 0; i < dataRecord.FieldCount; i++)
{
PropertyInfo propertyInfo = typeof(T).GetProperty(dataRecord.GetName(i));
Label endIfLabel = generator.DefineLabel();

if (propertyInfo != null && propertyInfo.GetSetMethod() != null)
{
generator.Emit(OpCodes.Ldarg_0);
generator.Emit(OpCodes.Ldc_I4, i);
generator.Emit(OpCodes.Callvirt, isDBNullMethod);
generator.Emit(OpCodes.Brtrue, endIfLabel);

generator.Emit(OpCodes.Ldloc, result);
generator.Emit(OpCodes.Ldarg_0);
generator.Emit(OpCodes.Ldc_I4, i);
generator.Emit(OpCodes.Callvirt, getValueMethod);

bool isNullable = false;
if (propertyInfo.PropertyType.Name.ToLower().Contains("nullable"))
isNullable = true;
Type _type = dataRecord.GetFieldType(i);
if (isNullable)
generator.Emit(OpCodes.Unbox_Any, types[_type]);
else
generator.Emit(OpCodes.Unbox_Any, _type);

generator.Emit(OpCodes.Callvirt, propertyInfo.GetSetMethod());

generator.MarkLabel(endIfLabel);
}
}

generator.Emit(OpCodes.Ldloc, result);
generator.Emit(OpCodes.Ret);

dynamicBuilder.handler = (Load)method.CreateDelegate(typeof(Load));
return dynamicBuilder;
}
}
...全文
423 12 打赏 收藏 转发到动态 举报
写回复
用AI写文章
12 条回复
切换为时间正序
请发表友善的回复…
发表回复
heyylu 2013-05-27
  • 打赏
  • 举报
回复
楼上终于可以了的,不能能发完整的代码! heyyfeng@163.com Thank you.
事理 2012-09-26
  • 打赏
  • 举报
回复
[Quote=引用 10 楼 的回复:]

嘿哥们,你还是用动态编译吧,堆IL太繁琐了
[/Quote]
动态编译速度没IL快吧,有没有相关例子。
abcayad 2012-09-26
  • 打赏
  • 举报
回复
嘿哥们,你还是用动态编译吧,堆IL太繁琐了
事理 2012-08-31
  • 打赏
  • 举报
回复

终于可以了,太感谢前辈了,现在先简单的判断一下可空类型,以后有空的时候再学习一下其它类型判断

Type memberType = propertyInfo.PropertyType;
Type nullUnderlyingType = Nullable.GetUnderlyingType(memberType);
Type unboxType = nullUnderlyingType != null ? nullUnderlyingType : memberType;

if (unboxType == typeof(byte[]) || unboxType == typeof(string))
{
il.Emit(OpCodes.Castclass, memberType);
}
else
{
il.Emit(OpCodes.Unbox_Any, dataRecord.GetFieldType(i));
if (nullUnderlyingType != null)
{
il.Emit(OpCodes.Newobj, memberType.GetConstructor(new[] { nullUnderlyingType }));
}
}


qldsrx 2012-08-31
  • 打赏
  • 举报
回复
给你一段未测试代码,只做了最基本的判断:

Type memberType = propertyInfo.PropertyType;
Type nullUnderlyingType = Nullable.GetUnderlyingType(memberType);
Type unboxType = nullUnderlyingType != null ? nullUnderlyingType : memberType;

if (unboxType == typeof(byte[]) || unboxType == typeof(string))
{
generator.Emit(OpCodes.Castclass, memberType);
}
else
{
generator.Emit(OpCodes.Unbox_Any, unboxType);
if (nullUnderlyingType != null)
{
generator.Emit(OpCodes.Newobj, memberType.GetConstructor(new[] { nullUnderlyingType }));
}
}
qldsrx 2012-08-31
  • 打赏
  • 举报
回复
你用原来的if (nullUnderlyingType != null)就是判断可空类型了呀。
我之所以不想在你的代码上面修改,因为它只判断了可空类型,而没有判断是否为byte[],这种类型虽然不需要考虑Nullable<>的情况,但是由于它不是值类型的,因此无法进行拆箱动作,用代码说就是你的
else
{
generator.Emit(OpCodes.Unbox_Any, _type);
}

对那个byte[]类型将失败,直接内存出错(显然也不会走上面那个可空类型的解析)。
对于具体数据类型最好具体判断,至少要把byte[]类型单独排除考虑,否则Emit产生的方法执行过程报错,你就只能看到内存错误了。
事理 2012-08-31
  • 打赏
  • 举报
回复
没人会吗?
事理 2012-08-31
  • 打赏
  • 举报
回复
[Quote=引用 4 楼 的回复:]

你的这段代码太过简陋了,少了很多判断,基本上执行会频繁出错,还不如用我那个SqlMapper呢,如果你能看懂的话,自己改下,上次发的那个SqlMapper有点小问题,一个null的地方没判断,断点可以调试出的。下次有机会再发第二版吧,一直在优化查错中,这东西优化起来简直是无底洞。
[/Quote]

项目是2008开发的,将参数dynamic obj修改为object obj后会报错误
private static T ConvertObj<T>(object obj)
{
return (T)obj;
}
前辈能不能帮忙把我贴的代码加一个可空类型的判断。


我是这样改的,但是总报内存错误


Type _type = dataRecord.GetFieldType(i);

Type memberType = propertyInfo.PropertyType;
Type nullUnderlyingType = Nullable.GetUnderlyingType(memberType);
//可空类型
if (propertyInfo.PropertyType.IsGenericType && propertyInfo.PropertyType.GetGenericTypeDefinition() == typeof(Nullable<>))
//if (nullUnderlyingType != null)
{
generator.Emit(OpCodes.Newobj, memberType.GetConstructor(new[] { nullUnderlyingType }));
//generator.Emit(OpCodes.Unbox_Any, nullUnderlyingType);
//generator.Emit(OpCodes.Newobj, propertyInfo.PropertyType.GetConstructor(new[] { nullUnderlyingType }));
}
else
{
generator.Emit(OpCodes.Unbox_Any, _type);
}

generator.Emit(OpCodes.Callvirt, propertyInfo.GetSetMethod());
generator.MarkLabel(endIfLabel);

qldsrx 2012-08-30
  • 打赏
  • 举报
回复
你的这段代码太过简陋了,少了很多判断,基本上执行会频繁出错,还不如用我那个SqlMapper呢,如果你能看懂的话,自己改下,上次发的那个SqlMapper有点小问题,一个null的地方没判断,断点可以调试出的。下次有机会再发第二版吧,一直在优化查错中,这东西优化起来简直是无底洞。
事理 2012-08-30
  • 打赏
  • 举报
回复
搞不定啊,总是报内存错误。
事理 2012-08-30
  • 打赏
  • 举报
回复
[Quote=引用 1 楼 的回复:]

你可以参考我之前发过的SqlMapper,博客里自己找。

这里给你点提示:
C# code
var memberType = propertyInfo.PropertyType;
var nullUnderlyingType = Nullable.GetUnderlyingType(memberType);
var unboxType = nullUnderlyingType != n……
[/Quote]

太感谢了,先看看。
qldsrx 2012-08-30
  • 打赏
  • 举报
回复
你可以参考我之前发过的SqlMapper,博客里自己找。

这里给你点提示:
var memberType = propertyInfo.PropertyType;
var nullUnderlyingType = Nullable.GetUnderlyingType(memberType);
var unboxType = nullUnderlyingType != null ? nullUnderlyingType : memberType;


判断数据类型请用unboxType,判断是否为可空类型只要判断nullUnderlyingType是否为null。
如果判断出是可空类型,在用unboxType进行封装,代码如下:
generator.Emit(OpCodes.Newobj, memberType.GetConstructor(new[] { nullUnderlyingType }));

110,499

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • Web++
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧