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 = ,
/// <summary>
/// 检查原属性默认值
/// </summary>
CheckOldValueDefault = ,
/// <summary>
/// 当属性值改变时重新赋值
/// </summary>
ReadOnValueChanged = ,
/// <summary>
/// 当属性值改变时重新赋值(检查属性默认值)
/// </summary>
ReadOnValueChangedCheckOldValueDefault =
}
}

接下来是具体实现:

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[]); 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[]); 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;
} }
}

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

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代码已经被修改了

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

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

不管怎么说,效果是有的

基于Mono.Cecil的静态注入的更多相关文章

  1. Mono.Cecil 初探(一):实现AOP

    序言 本篇文章介绍基于Mono.Cecil实现静态AOP的两种方式:无交互AOP和交互式AOP. 概念介绍 Mono.Cecil:一个可加载并浏览现有程序集并进行动态修改并保存的.NET框架. AOP ...

  2. 使用Mono Cecil 动态获取运行时数据 (Atribute形式 进行注入 用于写Log) [此文报考 xxx is declared in another module and needs to be imported的解决方法]-摘自网络

    目录 一:普通写法 二:注入定义 三:Weave函数 四:参数构造 五:业务编写 六:注入调用 7.  怎么调用别的程序集的方法示例 8. [is declared in another module ...

  3. 编译时MSIL注入--实践Mono Cecil(1)

    原文:编译时MSIL注入--实践Mono Cecil(1) 紧接上两篇浅谈.NET编译时注入(C#-->IL)和浅谈VS编译自定义编译任务—MSBuild Task(csproject),在第一 ...

  4. 教你怎么用Mono Cecil - 动态注入 (注意代码的注释)

    原文 教你怎么用Mono Cecil - 动态注入 (注意代码的注释) 使用 Mono Cecil 进行反编译:using Mono.Cecil; using Mono.Cecil.Cil; //.. ...

  5. 日志系统实战(一)—AOP静态注入

    背景 近期在写日志系统,需要在运行时在函数内注入日志记录,并附带函数信息,这时就想到用Aop注入的方式. AOP分动态注入和静态注入两种注入的方式. 动态注入方式 利用Remoting的Context ...

  6. Mono.Cecil

    Mono Cecil十分强大,强大到可以静态注入程序集(注入后生成新的程序集)和动态注入程序集(注入后不改变目标程序集,只在运行时改变程序集行为),它甚至可以用来调试PDB MDB调试符号格式文件. ...

  7. 运用Mono.Cecil 反射读取.NET程序集元数据

    CLR自带的反射机智和API可以很轻松的读取.NET程序集信息,但是不能对程序集进行修改.CLR提供的是只读的API,但是开源项目Mono.Cecil不仅仅可以读取.NET程序集的元数据,还可以进行修 ...

  8. 利用Mono.Cecil动态修改程序集来破解商业组件(仅用于研究学习)

    原文 利用Mono.Cecil动态修改程序集来破解商业组件(仅用于研究学习) Mono.Cecil是一个强大的MSIL的注入工具,利用它可以实现动态创建程序集,也可以实现拦截器横向切入动态方法,甚至还 ...

  9. 使用 Mono.Cecil 辅助 Unity3D 手游进行性能测试

    Unity3D 引擎在  UnityEngine 名字空间下,提供了  Profiler 类(Unity 5.6 开始似乎改变了这个名字空间),用于辅助对项目性能进行测试.以 Android 平台为例 ...

随机推荐

  1. Focus, w/o disturbance

    Focus = Aim + Execution + Persistence Disturbance = Disappointment + Anxiety + Failure

  2. [ASE]sprint3 总结 & sprint4计划

    斯普润特4! 啊终于到最后一个阶段了…… 有种苦日子就要熬到头跟小组合作意犹未尽的感觉 那么开始sprint3-sprint4的衔接吐槽总结 在之前的两周也就是sprint3期间正赶上出国申请的dl, ...

  3. 视频教程--ASP.NET MVC 使用 Petapoco 微型ORM框架+NpgSql驱动连接 PostgreSQL数据库

    说好的给园子里的朋友们录制与<ASP.NET MVC 使用 Petapoco 微型ORM框架+NpgSql驱动连接 PostgreSQL数据库> 这篇博客相对应的视频,由于一个月一来没有时 ...

  4. 【Bugly 技术干货】Android开发必备知识:为什么说Kotlin值得一试

    1.Hello, Kotlin Bugly 技术干货系列内容主要涉及移动开发方向,是由 Bugly邀请腾讯内部各位技术大咖,通过日常工作经验的总结以及感悟撰写而成,内容均属原创,转载请标明出处. 1. ...

  5. 软件测试基本理论-IBM模式

    软件测试基本理论(1) IBM生产模式 1   参考书目 <IBM-从菜鸟到测试架构师-一个测试工程师的成长日记> 出版社:电子工业出版社 印次:2013年6月 作者:IBM主要工程师 2 ...

  6. C# 获取当前日期在指定日期范围内是第几周

    public static int GetWeekOfDay(DateTime start, DateTime end) { //总周数 )); //用于存储日期 var weekDic = new ...

  7. Java基础类型总结

    最近一直在总结反思自己, 趁着现在请假在学校上课的空余时间,从基础开始重新温故学习下Java,充实下自己. 一.数据类型 从下图中,我们可以很清晰的看出Java中的类型,其中红色方框中的是Java的4 ...

  8. 《OOC》笔记(0)——为何要看这本书

    <OOC>笔记(0)——为何要看这本书 <OOC>全名是<Object-oriented Programming with ANSI-C>,作者Axel-Tobia ...

  9. 细说.NET中的多线程 (四 使用锁进行同步)

    通过锁来实现同步 排它锁主要用来保证,在一段时间内,只有一个线程可以访问某一段代码.两种主要类型的排它锁是lock和Mutex.Lock和Mutex相比构造起来更方便,运行的也更快.但是Mutex可以 ...

  10. ECMAScript5 Object的新属性方法

    虽然说现在并不是所有的浏览器都已经支持ECMAScript5的新特性,但相比于ECMAScript4而言ECMAScript5被广大浏览器厂商广泛接受,目前主流的浏览器中只有低版本的IE不支持,其它都 ...