zoukankan      html  css  js  c++  java
  • 反射的Emit实现(2)

    考虑了一下,将字段实现给贴了出来,但是说实话,我琢磨不定哪一个是最佳方案(原因如下)。

    代码
     public class User
        {
            
    internal string _username;
            
    public string Username { get { return this._username; } set { this._username = value; } }

            
    internal int? _id;
            
    public int? ID { get { return this._id; } set { this._id = value; } }
        }

    也就是说,字段必须是internal属性。 囧~~

    代码

        
    public class FieldProperty<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 FieldProperty(T owner)
            {
                
    this._owner = owner;
                
    this._ownerType = typeof(T);
            }

            
    private Dictionary<int, SetValueDelegateHandler> _cache = new Dictionary<int, SetValueDelegateHandler>();
            
    public void SetPropertyValue(string propertyName, object value)
            {
                SetValueDelegateHandler sv;
                
    int hashCode = propertyName.GetHashCode();
                
    if (this._cache.ContainsKey(hashCode))
                {
                    sv = this._cache[hashCode];
                }
                
    else
                {

                    
    string fieldName = "_" + propertyName;

                    var filedInfo = this._ownerType.GetField(fieldName, BindingFlags.Instance | BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.NonPublic);

                    
    // 创建动态函数
                    DynamicMethod method = new DynamicMethod("EmitCallable"nullnew Type[] { this._ownerType, ParameterType }, this._ownerType.Module);
                    
    // 获取动态函数的 IL 生成器
                    var il = method.GetILGenerator();
                    
    // 创建一个本地变量,主要用于 Object Type to Propety Type
                    var local = il.DeclareLocal(filedInfo.FieldType, true);
                    
    // 加载第 2 个参数【(T owner, object value)】的 value
                    il.Emit(OpCodes.Ldarg_1);
                    
    if (filedInfo.FieldType.IsValueType)
                    {
                        il.Emit(OpCodes.Unbox_Any, filedInfo.FieldType);// 如果是值类型,拆箱 string = (string)object;
                    }
                    
    else
                    {
                        il.Emit(OpCodes.Castclass, filedInfo.FieldType);// 如果是引用类型,转换 Class = object as Class
                    }

                    il.Emit(OpCodes.Stloc, local);// 将上面的拆箱或转换,赋值到本地变量,现在这个本地变量是一个与目标函数相同数据类型的字段了。
                    il.Emit(OpCodes.Ldarg_0);   // 加载第一个参数 owner
                    il.Emit(OpCodes.Ldloc, local);// 加载本地参数
                    il.Emit(OpCodes.Stfld, filedInfo);//调用字段,新值赋予旧值
                    il.Emit(OpCodes.Ret);   // 返回
                    /* 生成的动态函数类似:
                     * void EmitCallable(T owner, object value)
                     * {
                     *     T local = (T)value;
                     *     owner.Field = local;
                     * }
                     
    */
                    sv = method.CreateDelegate(typeof(SetValueDelegateHandler)) as SetValueDelegateHandler;
                    
    this._cache.Add(hashCode, sv);
                }

                sv(this._owner, value);
            }
        }
  • 相关阅读:
    [Linux] crontab和shell每天定时备份数据库
    [Go] 实战项目在线客服GO-FLY -在gin框架使用IP识别库转换IP为城市
    [javascript] elementui和vue下复制粘贴上传图片
    [Go] GO-FLY客服项目被公众号 "转角遇到GitHub " 推荐
    [javascript] cdn模式下vue和vue-router实现路由
    [Go] Golang发送http GET请求
    [MySQL] 利用explain查看sql语句中使用的哪个索引
    [Go]GO语言实战-小程序或公众号接口gin框架验证微信服务器消息签名-开源WEB客服
    [Go]GO语言实战-开源WEB客服GO-FLY-gorm下分页的实现
    [前端] 设定为disabled的表单域值不能被提交
  • 原文地址:https://www.cnblogs.com/sofire/p/1755415.html
Copyright © 2011-2022 走看看