反射的Emit实现

反射的 Emit实现

在日常开发中,我们频繁用到反射,除了最“繁重”的原始反射方式(这里不讲解),以及 4.0的关键字dynamic,还有许多的方式(Emit以及Linq)。接下来的演示,我将着重对以下这个类进行操作。

public   class  User
    {
        
public   string  Username {  get set ; }
    }

 

 

这是一个普通到不能再普通的类。我们要做的工作就是将Username属性进行赋值。在以往的反射,这个性能恐怕令人难以接受

首先说第一种,不说,直接贴代码,代码中有详细注释。

ExpandedBlockStart.gif 代码
         delegate   void  SetValueDelegate( string  u);
        
static   void  Work3()
        {
            User u 
=   new  User();

            
string  methodName  =   " set_Username " ;                      //  获取函数(命名约束)
            var method  =  u.GetType().GetMethod(methodName);          //  查找函数
            var type  =  method.GetParameters()[ 0 ].ParameterType;      //  返回第一个参数的数据类型

            var parameter 
=  Expression.Parameter(type,  " value " );     //  创建一个表达式参数
            
//  创建指定 实例、函数、参数 的调用函数
            var callExpression  =  Expression.Call(Expression.Constant(u), method, parameter);
            
//  创建调用函数的表达式
            Expression < SetValueDelegate >  lambdaExpression  =  Expression.Lambda < SetValueDelegate > (callExpression, parameter);
            SetValueDelegate dd 
=  lambdaExpression.Compile(); //  生成可执行函数的委托。

            Stopwatch watch 
=   new  Stopwatch();
            watch.Start();
            
for  ( int  i  =   0 ; i  <  Count; i ++ )
            {
                dd(
" Hello2 " );
            }
            watch.Stop();
            Console.WriteLine(
" Work3 Linq Expression:\t{0} " , watch.Elapsed.ToString());
        }

 

 

 

Linq反射的性能十分可观,一般来说只有直接调用的3-6倍的损失(不包括创建委托的那些)。可是这样有一个缺点,就是说,有些时候我们并不知道“属性”的数据类型是什么,这种情况下的Linq反射就显得有点鸡肋。

Emit,反射中性能损失最小,基本保持在2-4倍的损失。其实Linq反射的内部也是调用Emit

 

ExpandedBlockStart.gif 代码
  public   class  FastProperty < T >
    {
        
public   delegate   void  SetValueDelegateHandler(T owner,  object  value);
        
private   readonly  Type ParameterType  =   typeof ( object );

        
private  T _owner;
        
public  T Owner {  get  {  return   this ._owner; } }

        
private  Type _ownerType;

        
public  FastProperty(T owner)
        {
            
this ._owner  =  owner;
            
this ._ownerType  =   typeof (T);
        }


        
public  SetValueDelegateHandler SetPropertyValue( string  propertyName,  object  value)
        {

            
//  指定函数名
             string  methodName  =   " set_ "   +  propertyName;
            
//  搜索函数,不区分大小写 IgnoreCase
            var callMethod  =   this ._ownerType.GetMethod(methodName, BindingFlags.Instance  |  BindingFlags.IgnoreCase  |  BindingFlags.Public  |  BindingFlags.NonPublic);
            
//  获取参数
            var para  =  callMethod.GetParameters()[ 0 ];
            
//  创建动态函数
            DynamicMethod method  =   new  DynamicMethod( " EmitCallable " null new  Type[] {  this ._ownerType, ParameterType },  this ._ownerType.Module);
            
//  获取动态函数的 IL 生成器
            var il  =  method.GetILGenerator();
            
//  创建一个本地变量,主要用于 Object Type to Propety Type
            var local  =  il.DeclareLocal(para.ParameterType,  true );
            
//  加载第 2 个参数【(T owner, object value)】的 value
            il.Emit(OpCodes.Ldarg_1);
            
if  (para.ParameterType.IsValueType)
            {
                il.Emit(OpCodes.Unbox_Any, para.ParameterType);
//  如果是值类型,拆箱 string = (string)object;
            }
            
else
            {
                il.Emit(OpCodes.Castclass, para.ParameterType);
//  如果是引用类型,转换 Class = object as Class
            }
            il.Emit(OpCodes.Stloc, local);
//  将上面的拆箱或转换,赋值到本地变量,现在这个本地变量是一个与目标函数相同数据类型的字段了。
            il.Emit(OpCodes.Ldarg_0);    //  加载第一个参数 owner
            il.Emit(OpCodes.Ldloc, local); //  加载本地参数
            il.EmitCall(OpCodes.Callvirt, callMethod,  null ); // 调用函数
            il.Emit(OpCodes.Ret);    //  返回
             /*  生成的动态函数类似:
             * void EmitCallable(T owner, object value)
             * {
             *     T local = (T)value;
             *     owner.Method(local);
             * }
             
*/
            
return  method.CreateDelegate( typeof (SetValueDelegateHandler))  as  SetValueDelegateHandler;


        }
    }

 

 

 

我测试了一下,不知道怎么回事,明明在动态函数里执行了“拆箱”,速度却比指定数据类型,还要快。奇怪……

上面只是演示了一个动态属性赋值(其实是调用函数)的示例,当然你更可以来一个命名约束:

      private string _name;

        public string Name { get { return this._name; } set { this._name = value; } }

然后对字段 _name进行复制。

 

最后唠叨一句,如果您觉得我的文章有纯在“误解他人”的地方,欢迎指出,只有批评,才有成长。

 

 

 

 

 

转载于:https://www.cnblogs.com/sofire/archive/2010/06/10/1755357.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值