• 基于Mono.Cecil的静态注入


    Aop注入有2种方式:动态注入和静态注入,其中动态注入有很多实现了

    动态注入有几种方式:

    1. 利用Remoting的ContextBoundObject或MarshalByRefObject。
    2. 动态代理(反射),很多AOP框架都用这种方式。
    3. MVC的filter,也是反射。

    这里主要介绍静态注入

    ==========================================================================================

    起初的想法是实现一种功能,自动给对象的属性一个默认值,想来想去没有什么好的解决方法,参考资料后决定使用Mono.Cecil修改生成的程序集来实现!

    先定义一个接口

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Linq.Expressions;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace System.Linq
    {
    
        /// <summary>
        /// 支持注入
        /// </summary>
        /// <typeparam name="T"></typeparam>
        internal interface IInject<T>
        {
            /// <summary>
            /// 注入属性
            /// </summary>
            /// <typeparam name="TKey"></typeparam>
            /// <param name="name"></param>
            /// <param name="value"></param>
            /// <returns></returns>
            IInject<T> InjectProperty<TKey>(Expression<Func<T, TKey>> propertyName, Expression<Func<T, TKey>> propertyValue, InjectType type);
    
        }
    }

    定义一个描述类:

        internal class InjectItem
        {
    
            public string Name { get; set; }
    
            /// <summary>
            /// 表示生成的字段
            /// </summary>
            public FieldDefinition Field { get; set; }
            /// <summary>
            /// 标识生成字段成功
            /// </summary>
            public FieldDefinition SetOKField { get; set; }
            /// <summary>
            /// 标识
            /// </summary>
            public FieldDefinition ValueField { get; set; }
    
            public Type FieldType { get; set; }
    
            public Type Type { get; set; }
    
            public Delegate Value { get; set; }
    
            public MethodReference Method { get; set; }
    
        }

    定义一个缓存帮助类,存放程序集的一些数据:

    using Mono.Cecil;
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace System
    {
        internal class CacheHelper
        {
    
            internal static readonly ICache<string, TupleCache<AssemblyDefinition, bool>> _assembly = CacheFactory.CreateCache<string, TupleCache<AssemblyDefinition, bool>>();
    
    
            internal static readonly List<InjectItem> _setValue = new List<InjectItem>();
    
            /// <summary>
            /// 得到唯一程序集
            /// </summary>
            /// <param name="type"></param>
            /// <returns></returns>
            internal static TupleCache<AssemblyDefinition, bool> GetAssembly(Type type)
            {
                var ass = type.Assembly;
                var path = ass.CodeBase.TrimStart("file:///".ToCharArray());
                return _assembly.Get(path, () =>
                {
                    return new TupleCache<AssemblyDefinition, bool>(AssemblyDefinition.ReadAssembly(path), false);
                });
            }
        }
    }
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace System
    {
        internal class TupleCache<T1, T2>
        {
            public TupleCache(T1 item1, T2 item2)
            {
                Item1 = item1;
                Item2 = item2;
            }
    
            public T1 Item1 { get; set; }
    
            public T2 Item2 { get; set; }
        }
    }

    定义一个枚举,标识怎么处理映射:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace System.Linq
    {
        /// <summary>
        /// 指定注入类型
        /// </summary>
        //[Flags]
        public enum InjectType
        {
            /// <summary>
            /// 忽略原属性值
            /// </summary>
            IgnoreOldValue = 1,
            /// <summary>
            /// 检查原属性默认值
            /// </summary>
            CheckOldValueDefault = 2,
            /// <summary>
            /// 当属性值改变时重新赋值
            /// </summary>
            ReadOnValueChanged = 3,
            /// <summary>
            /// 当属性值改变时重新赋值(检查属性默认值)
            /// </summary>
            ReadOnValueChangedCheckOldValueDefault = 4
        }
    }

    接下来是具体实现:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using System.Reflection.Emit;
    using System.Linq.Expressions;
    using System.Reflection;
    using Mono.Cecil;
    using System.Collections;
    using System.Collections.ObjectModel;
    using Mono.Cecil.Cil;
    
    namespace System.Linq
    {
        internal class InjectItem
        {
    
            public string Name { get; set; }
    
            /// <summary>
            /// 表示生成的字段
            /// </summary>
            public FieldDefinition Field { get; set; }
            /// <summary>
            /// 标识生成字段成功
            /// </summary>
            public FieldDefinition SetOKField { get; set; }
            /// <summary>
            /// 标识
            /// </summary>
            public FieldDefinition ValueField { get; set; }
            /// <summary>
            /// 字段类型
            /// </summary>
            public Type FieldType { get; set; }
            /// <summary>
            /// 属性类型
            /// </summary>
            public Type Type { get; set; }
    
            public Delegate Value { get; set; }
    
            public MethodReference Method { get; set; }
    
        }
    
        internal sealed class InjectBase<T> : IInject<T>
        {
            /// <summary>
            /// 生成的字段名
            /// </summary>
    
            static readonly string _fieldName = "___Inject_Property_Name_{0}___";
    
            static readonly string _setFieldName = "___Inject_Property_Name_{0}___OK";
    
            static readonly string _methodName = "___Inject_Method_CheckDefaultValue___";
    
            Collection<InjectItem> _injectItems = new Collection<InjectItem>();
    
    
            internal InjectBase()
            {
                _type = typeof(T);
                if (_type.IsNested)
                {
                    throw new ArgumentException(_type.FullName + " is a private class!");
                }
                _assemby = CacheHelper.GetAssembly(_type);
                _typeDefinition = GetTypeFromAssembly();
                if (_typeDefinition == null)
                {
                    throw new ArgumentException("type is undefined!");
                }
    
            }
            /// <summary>
            /// 要处理的类型
            /// </summary>
            Type _type;
    
            /// <summary>
            /// 当前类型所对应的Mono.Cecil描述程序集
            /// </summary>
    
            TupleCache<AssemblyDefinition, bool> _assemby;
    
            /// <summary>
            /// 当前类型对应的Mono.Cecil描述类型
            /// </summary>
            TypeDefinition _typeDefinition;
    
            /// <summary>
            /// 获取类型对应的Mono.Cecil描述类型
            /// </summary>
            /// <returns></returns>
            TypeDefinition GetTypeFromAssembly()
            {
                foreach (var item in _assemby.Item1.Modules)
                {
                    var type = item.Types.FirstOrDefault(o => o.FullName == _type.FullName);
                    if (type != null)
                    {
                        return type;
                    }
                }
                return null;
            }
    
    
    
            Tuple<InjectItem, bool> OnInject<TKey>(Expression<Func<T, TKey>> propertyName, Expression<Func<T, TKey>> propertyValue)
            {
                //if (!typeof(MemberExpression).IsAssignableFrom(propertyName.Body.GetType()) && propertyName.Body.GetType().Name != "PropertyExpression")
                if (propertyName.Body.GetType().Name != "PropertyExpression")
                {
                    throw new ArgumentException("propertyName is not a property expression!");
                }
    
    
                var body = propertyName.Body as MemberExpression;
    
                string name = body.Member.Name;
    
                //指示是否处理过了当前类型
                TypeDefinition newType = _assemby.Item1.MainModule.Types.FirstOrDefault(o => o.FullName == InjectMap._classType.Item1 + "." + InjectMap._classType.Item2);
    
                //字段
                string fieldName = string.Format(_fieldName, name);
    
                if (newType != null)
                {
                    //处理过类型的其他属性了
    
                    //看看是否处理了当前属性
                    var injectItem1 = _injectItems.FirstOrDefault(o => o.Name == fieldName);
                    if (injectItem1 == null)
                    {
                        //没处理
                        injectItem1 = new InjectItem()
                        {
                            Name = fieldName,
                            Type = _type
                        };
                        _injectItems.Add(injectItem1);
                        CacheHelper._setValue.Add(injectItem1);
                    }
                    return new Tuple<InjectItem, bool>(injectItem1, true);
                }
                _assemby.Item2 = true;
                //得到属性
                var property = _typeDefinition.Properties.FirstOrDefault(o => o.Name == name);
    
                var getMethod = property.GetMethod;
    
                var setMethod = property.SetMethod;
    
                //如果不可读
                if (getMethod == null)
                {
                    throw new ArgumentException("property " + name + " on " + _type.FullName + " is writeonly!");
                }
    
    
                var injectItem = _injectItems.FirstOrDefault(o => o.Name == fieldName);
    
                if (injectItem == null)
                {
                    var field = _typeDefinition.Fields.FirstOrDefault(o => o.Name == fieldName);
                    FieldDefinition valueField = null;
                    FieldDefinition setFieldOK = null;
                    if (field == null)
                    {
                        //field = new FieldDefinition(fieldName, Mono.Cecil.FieldAttributes.Private | Mono.Cecil.FieldAttributes.Static, new TypeReference("System", typeof(Func<T, TKey>).Name, ModuleDefinition.ReadModule(Assembly.GetAssembly(typeof(Func<T, TKey>)).Location), new ModuleReference("mscorlib.dll")));
    
                        field = new FieldDefinition(fieldName, Mono.Cecil.FieldAttributes.Private | Mono.Cecil.FieldAttributes.Static, _typeDefinition.Module.Import(typeof(Func<T, TKey>)));
    
                        valueField = new FieldDefinition(fieldName + "Value", Mono.Cecil.FieldAttributes.Private, property.PropertyType);
                        setFieldOK = new FieldDefinition(string.Format(_setFieldName, name), Mono.Cecil.FieldAttributes.Private, _typeDefinition.Module.Import(typeof(bool)));
                        _typeDefinition.Fields.Add(field);
                        _typeDefinition.Fields.Add(valueField);
                        _typeDefinition.Fields.Add(setFieldOK);
                        injectItem = new InjectItem()
                        {
                            Field = field,
                            ValueField = valueField,
                            Name = fieldName,
                            Type = _type,
                            FieldType = body.Member.DeclaringType,
                            SetOKField = setFieldOK,
                            Method = new MethodReference(fieldName, _typeDefinition.Module.Import(property.PropertyType), _typeDefinition.Module.Import(_typeDefinition))
                        };
                        _injectItems.Add(injectItem);
                        CacheHelper._setValue.Add(injectItem);
                    }
                    //else
                    //{
                    //    valueField = _typeDefinition.Fields.FirstOrDefault(o => o.Name == fieldName + "Value");
                    //    setFieldOK = _typeDefinition.Fields.FirstOrDefault(o => o.Name == string.Format(_setFieldName, name));
                    //}
    
                }
    
                ////DefaultMethod
    
                //var checkDefaultMethod = _typeDefinition.Methods.FirstOrDefault(o => o.Name == _methodName);
    
                //if (checkDefaultMethod == null)
                //{
                //    checkDefaultMethod = new MethodDefinition(_methodName, Mono.Cecil.MethodAttributes.Static | Mono.Cecil.MethodAttributes.Private, _typeDefinition.Module.Import(typeof(bool)));
                //}
    
                return new Tuple<InjectItem, bool>(injectItem, false);
            }
    
            public IInject<T> InjectProperty<TKey>(Expression<Func<T, TKey>> propertyName, Expression<Func<T, TKey>> propertyValue, InjectType type)
            {
                //预处理
                var item = OnInject(propertyName, propertyValue);
                //编译值
                item.Item1.Value = propertyValue.Compile();
                if (item.Item2)
                {
                    //已处理,不再继续
                    return this;
                }
                var body = propertyName.Body as MemberExpression;
                string name = body.Member.Name;
                var fieldName = string.Format(_fieldName, name);
                var fieldValueName = fieldName + "Value";
                //得到属性
                var property = _typeDefinition.Properties.FirstOrDefault(o => o.Name == name);
                var getMethod = property.GetMethod;
                getMethod.Body.Instructions.Clear();
                getMethod.Body.Variables.Add(new VariableDefinition("flag", _typeDefinition.Module.Import(typeof(bool))));
                getMethod.Body.Variables.Add(new VariableDefinition(fieldValueName, _typeDefinition.Module.Import(property.PropertyType)));
    
                //处理Get属性
                if (type == InjectType.CheckOldValueDefault || type == InjectType.ReadOnValueChangedCheckOldValueDefault)
                {
                    InjectPropertyInternalGetCheckDefault(item.Item1, getMethod, propertyName, propertyValue, type);
                }
                else
                {
                    InjectPropertyInternalGet(item.Item1, getMethod, propertyName, propertyValue, type);
                }
                var setMethod = property.SetMethod;
    
                if (setMethod != null)
                {
                    //处理Set属性
                    setMethod.Body.Instructions.Clear();
                    if (type == InjectType.CheckOldValueDefault || type == InjectType.ReadOnValueChangedCheckOldValueDefault)
                    {
                        InjectPropertyInternalSetCheckDefault(item.Item1, setMethod, propertyName, propertyValue, type);
                    }
                    else
                    {
                        InjectPropertyInternalSet(item.Item1, setMethod, propertyName, propertyValue, type);
                    }
                }
    
                return this;
            }
    
            IInject<T> InjectPropertyInternalGet<TKey>(InjectItem item, MethodDefinition method, Expression<Func<T, TKey>> propertyName, Expression<Func<T, TKey>> propertyValue, InjectType type)
            {
                method.Body.InitLocals = true;
                var iLProcessor = method.Body.GetILProcessor();
                iLProcessor.Emit(Mono.Cecil.Cil.OpCodes.Nop);
                iLProcessor.Emit(Mono.Cecil.Cil.OpCodes.Ldarg_0);
                iLProcessor.Emit(Mono.Cecil.Cil.OpCodes.Ldfld, item.SetOKField);
                iLProcessor.Emit(Mono.Cecil.Cil.OpCodes.Ldc_I4_0);
                //iLProcessor.Emit(Mono.Cecil.Cil.OpCodes.Ldfld, item.Item1.ValueField);
                //iLProcessor.Emit(Mono.Cecil.Cil.OpCodes.Ldnull);
                iLProcessor.Emit(Mono.Cecil.Cil.OpCodes.Ceq);
                iLProcessor.Emit(Mono.Cecil.Cil.OpCodes.Stloc_0);
                iLProcessor.Emit(Mono.Cecil.Cil.OpCodes.Ldloc_0);
    
    
    
                List<Instruction> trueInstruction = new List<Instruction>();
                trueInstruction.Add(Instruction.Create(Mono.Cecil.Cil.OpCodes.Nop));
                trueInstruction.Add(Instruction.Create(Mono.Cecil.Cil.OpCodes.Ldarg_0));
                trueInstruction.Add(Instruction.Create(Mono.Cecil.Cil.OpCodes.Ldsfld, item.Field));
                trueInstruction.Add(Instruction.Create(Mono.Cecil.Cil.OpCodes.Ldarg_0));
                var invokeMethod = _typeDefinition.Module.Import(typeof(Func<T, TKey>).GetMethod("Invoke"));
                trueInstruction.Add(Instruction.Create(Mono.Cecil.Cil.OpCodes.Callvirt, invokeMethod));
                trueInstruction.Add(Instruction.Create(Mono.Cecil.Cil.OpCodes.Stfld, item.ValueField));
                trueInstruction.Add(Instruction.Create(Mono.Cecil.Cil.OpCodes.Ldarg_0));
                trueInstruction.Add(Instruction.Create(Mono.Cecil.Cil.OpCodes.Ldc_I4_1));
                trueInstruction.Add(Instruction.Create(Mono.Cecil.Cil.OpCodes.Stfld, item.SetOKField));
                trueInstruction.Add(Instruction.Create(Mono.Cecil.Cil.OpCodes.Nop));
    
                List<Instruction> falseInstruction = new List<Instruction>();
                falseInstruction.Add(Instruction.Create(Mono.Cecil.Cil.OpCodes.Ldarg_0));
                falseInstruction.Add(Instruction.Create(Mono.Cecil.Cil.OpCodes.Ldfld, item.ValueField));
                falseInstruction.Add(Instruction.Create(Mono.Cecil.Cil.OpCodes.Stloc_1));
    
                iLProcessor.Emit(Mono.Cecil.Cil.OpCodes.Brfalse_S, falseInstruction[0]);
    
                foreach (var instruction in trueInstruction)
                {
                    iLProcessor.Append(instruction);
                }
    
                foreach (var instruction in falseInstruction)
                {
                    iLProcessor.Append(instruction);
                }
    
                Instruction endInstruction = Instruction.Create(Mono.Cecil.Cil.OpCodes.Ldloc_1);
                iLProcessor.Emit(Mono.Cecil.Cil.OpCodes.Br_S, endInstruction);
                iLProcessor.Append(endInstruction);
    
                iLProcessor.Emit(Mono.Cecil.Cil.OpCodes.Ret);
                return this;
            }
    
            IInject<T> InjectPropertyInternalGetCheckDefault<TKey>(InjectItem item, MethodDefinition method, Expression<Func<T, TKey>> propertyName, Expression<Func<T, TKey>> propertyValue, InjectType type)
            {
                var body = propertyName.Body as MemberExpression;
    
                //method.Body.Variables.Add(new VariableDefinition("flag2", _typeDefinition.Module.Import(typeof(bool))));
    
                //if (item.ValueField.FieldType.IsValueType)
                //{
                //    method.Body.Variables.Add(new VariableDefinition("defaultValue", _typeDefinition.Module.Import(body.Member.ReflectedType)));
                //}
                method.Body.InitLocals = true;
                var iLProcessor = method.Body.GetILProcessor();
                iLProcessor.Emit(Mono.Cecil.Cil.OpCodes.Nop);
    
                List<Instruction> flag1 = new List<Instruction>();
                flag1.Add(Instruction.Create(Mono.Cecil.Cil.OpCodes.Ldarg_0));
                flag1.Add(Instruction.Create(Mono.Cecil.Cil.OpCodes.Ldfld, item.SetOKField));
                flag1.Add(Instruction.Create(Mono.Cecil.Cil.OpCodes.Ldc_I4_0));
                flag1.Add(Instruction.Create(Mono.Cecil.Cil.OpCodes.Ceq));
                flag1.Add(Instruction.Create(Mono.Cecil.Cil.OpCodes.Stloc_0));
                flag1.Add(Instruction.Create(Mono.Cecil.Cil.OpCodes.Ldloc_0));
    
    
                //校验默认值
                if (!item.ValueField.FieldType.IsValueType)
                {
                    //iLProcessor.Emit(Mono.Cecil.Cil.OpCodes.Ldloc_2);
                }
                else
                {
                    var equalsMethod = _typeDefinition.Module.Import(typeof(object).GetMethod("Equals", BindingFlags.Static | BindingFlags.Public));
                    var getHashCodeMethod = _typeDefinition.Module.Import(body.Member.DeclaringType.GetMethod("GetHashCode"));
    
                    //iLProcessor.Emit(Mono.Cecil.Cil.OpCodes.Ldc_I4_0);
                    //iLProcessor.Emit(Mono.Cecil.Cil.OpCodes.Bne_Un_S, flag1[0]);
                    //iLProcessor.Emit(Mono.Cecil.Cil.OpCodes.Stloc_0);
                    //iLProcessor.Emit(Mono.Cecil.Cil.OpCodes.Ldloc_0);
                    //iLProcessor.Emit(Mono.Cecil.Cil.OpCodes.Bne_Un_S, flag1[0]);
    
    
                    //iLProcessor.Emit(Mono.Cecil.Cil.OpCodes.Ldfld, item.SetOKField);
                    //iLProcessor.Emit(Mono.Cecil.Cil.OpCodes.Ldc_I4_0);
                    //iLProcessor.Emit(Mono.Cecil.Cil.OpCodes.Bne_Un_S, flag1[0]);
                    //iLProcessor.Emit(Mono.Cecil.Cil.OpCodes.Ldarg_2);
                    //iLProcessor.Emit(Mono.Cecil.Cil.OpCodes.Ldfld, item.SetOKField);
                    //iLProcessor.Emit(Mono.Cecil.Cil.OpCodes.Ldc_I4_0);
    
                    //iLProcessor.Emit(Mono.Cecil.Cil.OpCodes.Ldarg_2);
                    //iLProcessor.Emit(Mono.Cecil.Cil.OpCodes.Ldc_I4_0);
                    //iLProcessor.Emit(Mono.Cecil.Cil.OpCodes.Callvirt, getHashCodeMethod);
                    //iLProcessor.Emit(Mono.Cecil.Cil.OpCodes.Ldc_I4_0);
                    //iLProcessor.Emit(Mono.Cecil.Cil.OpCodes.Ceq);
                    //iLProcessor.Emit(Mono.Cecil.Cil.OpCodes.Stloc_0);
                    //iLProcessor.Emit(Mono.Cecil.Cil.OpCodes.Ldloc_0);
                    //iLProcessor.Emit(Mono.Cecil.Cil.OpCodes.Ldc_I4_0);
                    //iLProcessor.Emit(Mono.Cecil.Cil.OpCodes.Callvirt, getHashCodeMethod);
    
                    //iLProcessor.Emit(Mono.Cecil.Cil.OpCodes.Ldfld, item.ValueField);
    
                    //iLProcessor.Emit(Mono.Cecil.Cil.OpCodes.Ldc_I4_0);
                    //iLProcessor.Emit(Mono.Cecil.Cil.OpCodes.Callvirt, getHashCodeMethod);
    
                    //iLProcessor.Emit(Mono.Cecil.Cil.OpCodes.Call, equalsMethod);
                }
    
    
                foreach (var instruction in flag1)
                {
                    iLProcessor.Append(instruction);
                }
    
                //iLProcessor.Emit(Mono.Cecil.Cil.OpCodes.Ldfld, item.SetOKField);
                //iLProcessor.Emit(Mono.Cecil.Cil.OpCodes.Ldc_I4_0);
                //iLProcessor.Emit(Mono.Cecil.Cil.OpCodes.Ceq);
                //iLProcessor.Emit(Mono.Cecil.Cil.OpCodes.Stloc_0);
                //iLProcessor.Emit(Mono.Cecil.Cil.OpCodes.Ldloc_0);
    
                //iLProcessor.Emit(Mono.Cecil.Cil.OpCodes.Ceq);
                //iLProcessor.Emit(Mono.Cecil.Cil.OpCodes.Stloc_0);
                //iLProcessor.Emit(Mono.Cecil.Cil.OpCodes.Ldloc_0);
    
                List<Instruction> trueInstruction = new List<Instruction>();
                trueInstruction.Add(Instruction.Create(Mono.Cecil.Cil.OpCodes.Nop));
                trueInstruction.Add(Instruction.Create(Mono.Cecil.Cil.OpCodes.Ldarg_0));
                trueInstruction.Add(Instruction.Create(Mono.Cecil.Cil.OpCodes.Ldsfld, item.Field));
                trueInstruction.Add(Instruction.Create(Mono.Cecil.Cil.OpCodes.Ldarg_0));
                var invokeMethod = _typeDefinition.Module.Import(typeof(Func<T, TKey>).GetMethod("Invoke"));
                trueInstruction.Add(Instruction.Create(Mono.Cecil.Cil.OpCodes.Callvirt, invokeMethod));
                trueInstruction.Add(Instruction.Create(Mono.Cecil.Cil.OpCodes.Stfld, item.ValueField));
                trueInstruction.Add(Instruction.Create(Mono.Cecil.Cil.OpCodes.Ldarg_0));
                trueInstruction.Add(Instruction.Create(Mono.Cecil.Cil.OpCodes.Ldc_I4_1));
                trueInstruction.Add(Instruction.Create(Mono.Cecil.Cil.OpCodes.Stfld, item.SetOKField));
                trueInstruction.Add(Instruction.Create(Mono.Cecil.Cil.OpCodes.Nop));
    
                List<Instruction> falseInstruction = new List<Instruction>();
                falseInstruction.Add(Instruction.Create(Mono.Cecil.Cil.OpCodes.Ldarg_0));
                falseInstruction.Add(Instruction.Create(Mono.Cecil.Cil.OpCodes.Ldfld, item.ValueField));
                falseInstruction.Add(Instruction.Create(Mono.Cecil.Cil.OpCodes.Stloc_1));
    
                iLProcessor.Emit(Mono.Cecil.Cil.OpCodes.Brfalse_S, falseInstruction[0]);
    
                foreach (var instruction in trueInstruction)
                {
                    iLProcessor.Append(instruction);
                }
    
                foreach (var instruction in falseInstruction)
                {
                    iLProcessor.Append(instruction);
                }
    
                Instruction endInstruction = Instruction.Create(Mono.Cecil.Cil.OpCodes.Ldloc_1);
                iLProcessor.Emit(Mono.Cecil.Cil.OpCodes.Br_S, endInstruction);
                iLProcessor.Append(endInstruction);
    
                iLProcessor.Emit(Mono.Cecil.Cil.OpCodes.Ret);
                return this;
            }
    
            IInject<T> InjectPropertyInternalSet<TKey>(InjectItem item, MethodDefinition method, Expression<Func<T, TKey>> propertyName, Expression<Func<T, TKey>> propertyValue, InjectType type)
            {
                var iLProcessor = method.Body.GetILProcessor();
                iLProcessor.Emit(Mono.Cecil.Cil.OpCodes.Ldarg_0);
                iLProcessor.Emit(Mono.Cecil.Cil.OpCodes.Ldarg_1);
                iLProcessor.Emit(Mono.Cecil.Cil.OpCodes.Stfld, item.ValueField);
                iLProcessor.Emit(Mono.Cecil.Cil.OpCodes.Ldarg_0);
                if (type == InjectType.IgnoreOldValue)
                {
                    iLProcessor.Emit(Mono.Cecil.Cil.OpCodes.Ldc_I4_1);
                }
                else if (type == InjectType.ReadOnValueChanged)
                {
                    iLProcessor.Emit(Mono.Cecil.Cil.OpCodes.Ldc_I4_0);
                }
                iLProcessor.Emit(Mono.Cecil.Cil.OpCodes.Stfld, item.SetOKField);
                iLProcessor.Emit(Mono.Cecil.Cil.OpCodes.Ret);
                //iLProcessor.Emit(Mono.Cecil.Cil.OpCodes.Stfld, item.ValueField);
                return this;
            }
    
            IInject<T> InjectPropertyInternalSetCheckDefault<TKey>(InjectItem item, MethodDefinition method, Expression<Func<T, TKey>> propertyName, Expression<Func<T, TKey>> propertyValue, InjectType type)
            {
                var iLProcessor = method.Body.GetILProcessor();
                iLProcessor.Emit(Mono.Cecil.Cil.OpCodes.Ldarg_0);
                iLProcessor.Emit(Mono.Cecil.Cil.OpCodes.Ldarg_1);
                iLProcessor.Emit(Mono.Cecil.Cil.OpCodes.Stfld, item.ValueField);
                iLProcessor.Emit(Mono.Cecil.Cil.OpCodes.Ldarg_0);
                if (type == InjectType.CheckOldValueDefault)
                {
                    iLProcessor.Emit(Mono.Cecil.Cil.OpCodes.Ldc_I4_1);
                }
                else if (type == InjectType.ReadOnValueChangedCheckOldValueDefault)
                {
                    iLProcessor.Emit(Mono.Cecil.Cil.OpCodes.Ldc_I4_0);
                }
                iLProcessor.Emit(Mono.Cecil.Cil.OpCodes.Stfld, item.SetOKField);
                iLProcessor.Emit(Mono.Cecil.Cil.OpCodes.Ret);
                //iLProcessor.Emit(Mono.Cecil.Cil.OpCodes.Stfld, item.ValueField);
                return this;
            }
    
        }
    }
    View Code

    以上就是主要代码,接下来给个入口就好了

    using Mono.Cecil;
    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using System.Web;
    
    namespace System.Linq
    {
    
        public abstract class InjectMap
        {
            /// <summary>
            /// 命名空间和类名,标识程序集已处理
            /// </summary>
            internal static readonly Tuple<string, string> _classType = new Tuple<string, string>("System.Inject", "Inject_Assemby_Over");
    
            static bool _isMap = false;
    
            internal static readonly ICache<Type, InjectMap> _cache = CacheFactory.CreateCache<Type, InjectMap>();
    
            /// <summary>
            /// 创建映射
            /// </summary>
            /// <typeparam name="T"></typeparam>
            /// <returns></returns>
            public static InjectMap<T> CreateMap<T>()
            {
                var map = _cache.Get(typeof(T), () => InjectMap<T>.Create()) as InjectMap<T>;
                return map;
            }
    
            /// <summary>
            /// 结束注入
            /// 注意:方法会自动检测是否需要注入数据
            /// 如果成功注入数据,则会重启应用程序
            /// 注入数据后不会再次注入了
            /// </summary>
            public static void End()
            {
                bool reload = false;
                foreach (var item in CacheHelper._assembly)
                {
                    if (item.Value.Item2)
                    {
                        reload = true;
                        item.Value.Item1.MainModule.Types.Add(new TypeDefinition(_classType.Item1, _classType.Item2, Mono.Cecil.TypeAttributes.Class | Mono.Cecil.TypeAttributes.Public, item.Value.Item1.MainModule.Import(typeof(object))));
                        item.Value.Item1.Write(item.Key);
                    }
                }
                if (reload)
                {
                    //会重启程序
                    CacheHelper._assembly.Flush();
                    CacheHelper._setValue.Clear();
                    _isMap = true;
    
                    if (HttpContext.Current != null)
                    {
                        //HttpRuntime.UnloadAppDomain();
                        //HttpRuntime.UnloadAppDomain();
                        File.SetLastWriteTime(System.Web.Hosting.HostingEnvironment.MapPath("~/web.config"), DateTime.Now);
                        //HttpContext.Current.Response.Redirect(HttpContext.Current.Request.Url.ToString());
                    }
                    return;
                }
                else if (!_isMap)
                {
                    //不重启程序,修改静态字段值
                    foreach (var item in CacheHelper._setValue)
                    {
                        item.Type.GetField(item.Name, Reflection.BindingFlags.Static | Reflection.BindingFlags.NonPublic).SetValue(null, item.Value);
                    }
                }
                _isMap = true;
                CacheHelper._assembly.Flush();
                CacheHelper._setValue.Clear();
            }
    
    
    #if DEBUG
            /// <summary>
            /// 结束注入
            /// </summary>
            public static void End(string testPath)
            {
                bool reload = false;
                foreach (var item in CacheHelper._assembly)
                {
                    if (item.Value.Item2)
                    {
                        reload = true;
                        item.Value.Item1.MainModule.Types.Add(new TypeDefinition(_classType.Item1, _classType.Item2, Mono.Cecil.TypeAttributes.Class | Mono.Cecil.TypeAttributes.Public));
                        item.Value.Item1.Write(item.Key + testPath + ".dll");
                    }
                }
                if (reload)
                {
                    _isMap = true;
                    if (HttpContext.Current != null)
                    {
                        //HttpRuntime.UnloadAppDomain();
                        HttpRuntime.UnloadAppDomain();
                        File.SetLastWriteTime(System.Web.Hosting.HostingEnvironment.MapPath("~/web.config"), DateTime.Now);
                        //HttpContext.Current.Response.Redirect(HttpContext.Current.Request.Url.ToString());
                    }
                    return;
                }
                else if (!_isMap)
                {
                    foreach (var item in CacheHelper._setValue)
                    {
                        item.Type.GetField(item.Name, Reflection.BindingFlags.Static | Reflection.BindingFlags.NonPublic).SetValue(null, item.Value);
                    }
                }
                _isMap = true;
            }
    #endif
    
        }
    
        /// <summary>
        /// 支持注入
        /// </summary>
        public sealed class InjectMap<T> : InjectMap
        {
    
            InjectMap() { }
            IInject<T> _inject;
    
            internal static InjectMap<T> Create()
            {
                InjectMap<T> map = new InjectMap<T>();
                map._inject = new InjectBase<T>();
                return map;
            }
    
            /// <summary>
            /// 注入属性值到指定类型中
            /// </summary>
            /// <typeparam name="TKey"></typeparam>
            /// <param name="propertyName">属性名表达式</param>
            /// <param name="propertyValue">属性值表达式</param>
            /// <returns></returns>
            public InjectMap<T> InjectProperty<TKey>(Expressions.Expression<Func<T, TKey>> propertyName, Expressions.Expression<Func<T, TKey>> propertyValue)
            {
                this._inject.InjectProperty(propertyName, propertyValue, InjectType.IgnoreOldValue);
                return this;
            }
    
            /// <summary>
            /// 注入属性值到指定类型中
            /// </summary>
            /// <typeparam name="TKey"></typeparam>
            /// <param name="propertyName">属性名表达式</param>
            /// <param name="propertyValue">属性值表达式</param>
            /// <param name="type">注入属性选项</param>
            /// <returns></returns>
            public InjectMap<T> InjectProperty<TKey>(Expressions.Expression<Func<T, TKey>> propertyName, Expressions.Expression<Func<T, TKey>> propertyValue, InjectType type)
            {
                this._inject.InjectProperty(propertyName, propertyValue, type);
                return this;
            }
        }
    
    
    
    
    }

    测试:

        public class TestClass
        {
            public string Name { get; set; }
    
            public int Id { get; set; }
    
    
            public bool IsDeleted { get; set; }
        }

    Application_Start中执行代码:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using System.Web;
    
    namespace Dai.CommonLib.WebTest.Models
    {
        class Register : IRegister
        {
            void IRegister.Register()
            {
                InjectMap.CreateMap<TestClass>().InjectProperty(o => o.Name, o => "test").InjectProperty(o => o.IsDeleted, o => !string.IsNullOrEmpty(o.Name));
                InjectMap.End();
            }
        }
    }

    控制器代码:

    using Dai.CommonLib.WebTest.Models;
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using System.Web.Mvc;
    
    namespace Dai.CommonLib.WebTest.Controllers
    {
        public class HomeController : Controller
        {
            // GET: Home
            public ActionResult Index()
            {
                TestClass testClass = new TestClass();
    
                return Content(testClass.ToJson());
            }
        }
    }

    看看效果

    第一次访问:

    {"Name":null,"Id":0,"IsDeleted":false}

    此时程序会重启,并且Mono.Cecil会修改已生成好的程序集(如果没有修改过的话)

    第二次及以后的访问:

    {"Name":"test","Id":0,"IsDeleted":true}

    这时候程序集的IL代码已经被修改了

    优点:使用方便,可以省去一些麻烦

    缺点:目前来看应用场景并不多,并且无法调试(因为程序集与源代码不匹配)!!!

    不管怎么说,效果是有的

  • 相关阅读:
    NET CORE EF事务
    搭建Vue-nuxt.js
    VUE获取URL(导航)参数方法
    第十二届蓝桥杯大赛软件赛决赛题解
    第十二届蓝桥杯大赛软件赛省赛第二场题解
    P1955 [NOI2015] 程序自动分析
    P1621 集合
    将博客搬至CSDN
    2021第六届GPLT 团体程序设计天梯赛CCCC 个人题解
    Divide by Zero 2021 and Codeforces Round #714 (Div. 2)
  • 原文地址:https://www.cnblogs.com/pokemon/p/5479509.html
Copyright © 2020-2023  润新知