例如NHibernate,使用Emit读取/设置实体属性时,生成的DynamicMethod每次读取/设置全部的属性值,读取时返回一个object[],设置时提供一个包含各个属性值的object[]数组。在SELECT时使用这种方式一次设置好所有属性;在INSERT、UPDATE时则一次读出全部属性;在DELETE时则可以直接使用反射从实体上读取identity属性,因为从应用层面总体来看反射的性能还是比较好的。
Emit跟反射的性能测试对比如下:
Emit、Reflection代码:
//A delegate for the dynamic method
public delegate object GetPropertyValueInvoker(object obj);
public class EmitTest
{
private static GetPropertyValueInvoker GetEmitInvoker(Type type, string propertyName)
{
PropertyInfo propInfo = type.GetProperty(propertyName
, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
//Create a DynamicMethod
Type ownerType = type.IsInterface ? typeof(object) : type;
bool canSkipChecks = SecurityManager.IsGranted(new ReflectionPermission(ReflectionPermissionFlag.MemberAccess));
DynamicMethod method = new DynamicMethod(string.Empty, typeof(object)
, new Type[] { typeof(object) }, ownerType, canSkipChecks);
//Use ILGenerator to build the method body’s IL code
ILGenerator il = method.GetILGenerator();
//Load the first argument of the method call onto stack
il.Emit(OpCodes.Ldarg_0);
//Necessary type conversion
if (type.IsValueType)
il.Emit(OpCodes.Unbox, type);
else [Page]
il.Emit(OpCodes.Castclass, type);
//Call the property’s get method
il.EmitCall(OpCodes.Callvirt, propInfo.GetGetMethod(true), null);
//If getter return a value type, box it to object
if (propInfo.PropertyType.IsValueType)
{
il.Emit(OpCodes.Box, propInfo.PropertyType);
}
//Return the value of the property
il.Emit(OpCodes.Ret);
//Create a delegate for the client to call the dynamic method
GetPropertyValueInvoker getInvoker =
(GetPropertyValueInvoker)method.CreateDelegate(typeof(GetPropertyValueInvoker));
return getInvoker;
}
//simply cache the dynamic method for the type TestEntity
private static IDictionary<string, GetPropertyValueInvoker> _invokerCache
= new Dictionary<string, GetPropertyValueInvoker>(3);
//Use the dynamic method, which is generated by using Emit every time, to get the property’s value
延伸阅读
文章来源于领测软件测试网 https://www.ltesting.net/