程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> C# >> C#入門知識 >> 基於Mono.Cecil的靜態注入,mono.cecil靜態

基於Mono.Cecil的靜態注入,mono.cecil靜態

編輯:C#入門知識

基於Mono.Cecil的靜態注入,mono.cecil靜態


Aop注入有2種方式:動態注入和靜態注入,其中動態注入有很多實現了

 

動態注入有幾種方式:

這裡主要介紹靜態注入

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

起初的想法是實現一種功能,自動給對象的屬性一個默認值,想來想去沒有什麼好的解決方法,參考資料後決定使用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代碼已經被修改了

 

 

優點:使用方便,可以省去一些麻煩

 

缺點:目前來看應用場景並不多,並且無法調試(因為程序集與源代碼不匹配)!!!

 

不管怎麼說,效果是有的

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved