基於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代碼已經被修改了
優點:使用方便,可以省去一些麻煩
缺點:目前來看應用場景並不多,並且無法調試(因為程序集與源代碼不匹配)!!!
不管怎麼說,效果是有的