using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Text;
using System.Threading;
namespace EmitCreateDynamicProxy
{
public class DynamicProxyGenerator
{
private const string DynamicAssemblyName = "DynamicAssembly";//动态程序集名称
private const string DynamicModuleName = "DynamicAssemblyModule";
private const string DynamicModuleDllName = "DynamicAssembly.dll";//动态模块名称
private const string ProxyClassNameFormater = "{0}Proxy";
private const string ModifiedPropertyNamesFieldName = "ModifiedPropertyNames";
private const MethodAttributes GetSetMethodAttributes = MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.CheckAccessOnOverride | MethodAttributes.Virtual | MethodAttributes.HideBySig;
///
/// 创建动态程序集,返回AssemblyBuilder
///
///
///
private static AssemblyBuilder DefineDynamicAssembly(bool isSavaDll = false)
{
//动态创建程序集
AssemblyName DemoName = new AssemblyName(DynamicAssemblyName);
AssemblyBuilderAccess assemblyBuilderAccess = isSavaDll ? AssemblyBuilderAccess.RunAndSave : AssemblyBuilderAccess.Run;
AssemblyBuilder dynamicAssembly = AppDomain.CurrentDomain.DefineDynamicAssembly(DemoName, assemblyBuilderAccess);
return dynamicAssembly;
}
///
/// 创建动态模块,返回ModuleBuilder
///
///
/// ModuleBuilder
private static ModuleBuilder DefineDynamicModule(AssemblyBuilder dynamicAssembly, bool isSavaDll = false)
{
ModuleBuilder moduleBuilder = null;
//动态创建模块
if (isSavaDll)
moduleBuilder = dynamicAssembly.DefineDynamicModule(DynamicModuleName, DynamicModuleDllName);
else
moduleBuilder = dynamicAssembly.DefineDynamicModule(DynamicModuleName);
return moduleBuilder;
}
///
/// 创建动态代理类,重写属性Get Set 方法,并监控属性的Set方法,把变更的属性名加入到list集合中,需要监控的属性必须是virtual
/// 如果你想保存修改的属性名和属性值,修改Set方法的IL实现
///
///
///
///
public static T CreateDynamicProxy(bool isSavaDynamicModule = false)
{
Type modifiedPropertyNamesType = typeof(HashSet);
Type typeNeedProxy = typeof(T);
AssemblyBuilder assemblyBuilder = DefineDynamicAssembly(isSavaDynamicModule);
//动态创建模块
ModuleBuilder moduleBuilder = DefineDynamicModule(assemblyBuilder, isSavaDynamicModule);
string proxyClassName = string.Format(ProxyClassNameFormater, typeNeedProxy.Name);
//动态创建类代理
TypeBuilder typeBuilderProxy = moduleBuilder.DefineType(proxyClassName, TypeAttributes.Public, typeNeedProxy);
//定义一个变量存放属性变更名
FieldBuilder fbModifiedPropertyNames = typeBuilderProxy.DefineField(ModifiedPropertyNamesFieldName, modifiedPropertyNamesType, FieldAttributes.Public);
//定义接口
var pt = typeof(PropertyChangedEventHandler);
typeBuilderProxy.AddInterfaceImplementation(typeof(INotifyPropertyChanged));
var eil = typeBuilderProxy.DefineEvent("PropertyChanged", EventAttributes.None, typeof(PropertyChangedEventHandler));
//add field
var eb = typeBuilderProxy.DefineField("PropertyChanged", typeof(PropertyChangedEventHandler), FieldAttributes.Private);
var compareExchange = GetGenericMethod(typeof(Interlocked), "CompareExchange");// finds the correct method to call.
// thanks to @marc, create the specific method with the correct type
compareExchange = compareExchange.MakeGenericMethod(typeof(PropertyChangedEventHandler));
//add methoed
var mas = MethodAttributes.Public | MethodAttributes.HideBySig
| MethodAttributes.NewSlot | MethodAttributes.SpecialName | MethodAttributes.Virtual | MethodAttributes.Final;
var mb = typeBuilderProxy.DefineMethod("add_PropertyChanged", mas, typeof(void), new Type[] { pt });
mb.DefineParameter(0, ParameterAttributes.Retval, null);
mb.DefineParameter(1, ParameterAttributes.In, "value");
var il = mb.GetILGenerator();
il.DeclareLocal(pt);
il.DeclareLocal(pt);
il.DeclareLocal(pt);
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Ldfld, eb);
il.Emit(OpCodes.Stloc_0);
var lable = il.DefineLabel();
il.MarkLabel(lable);
il.Emit(OpCodes.Ldloc_0);
il.Emit(OpCodes.Stloc_1);
il.Emit(OpCodes.Ldloc_1);
il.Emit(OpCodes.Ldarg_1);
il.Emit(OpCodes.Call, typeof(Delegate).GetMethod("Combine", new Type[] { typeof(Delegate), typeof(Delegate) }));
il.Emit(OpCodes.Castclass, typeof(PropertyChangedEventHandler));
il.Emit(OpCodes.Stloc_2);
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Ldflda, eb);
il.Emit(OpCodes.Ldloc_2);
il.Emit(OpCodes.Ldloc_1);
il.Emit(OpCodes.Call, compareExchange);
il.Emit(OpCodes.Stloc_0);
il.Emit(OpCodes.Ldloc_0);
il.Emit(OpCodes.Ldloc_1);
il.Emit(OpCodes.Bne_Un_S, lable);
il.Emit(OpCodes.Ret);
//remove event
mb = typeBuilderProxy.DefineMethod("remove_PropertyChanged", mas, typeof(void), new Type[] { pt });
mb.DefineParameter(0, ParameterAttributes.Retval, null);
mb.DefineParameter(1, ParameterAttributes.In, "value");
il = mb.GetILGenerator();
il.DeclareLocal(pt);
il.DeclareLocal(pt);
il.DeclareLocal(pt);
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Ldfld, eb);
il.Emit(OpCodes.Stloc_0);
lable = il.DefineLabel();
il.MarkLabel(lable);
il.Emit(OpCodes.Ldloc_0);
il.Emit(OpCodes.Stloc_1);
il.Emit(OpCodes.Ldloc_1);
il.Emit(OpCodes.Ldarg_1);
il.Emit(OpCodes.Call, typeof(Delegate).GetMethod("Remove", new Type[] { typeof(Delegate), typeof(Delegate) }));
il.Emit(OpCodes.Castclass, typeof(PropertyChangedEventHandler));
il.Emit(OpCodes.Stloc_2);
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Ldflda, eb);
il.Emit(OpCodes.Ldloc_2);
il.Emit(OpCodes.Ldloc_1);
il.Emit(OpCodes.Call, compareExchange);
il.Emit(OpCodes.Stloc_0);
il.Emit(OpCodes.Ldloc_0);
il.Emit(OpCodes.Ldloc_1);
il.Emit(OpCodes.Bne_Un_S, lable);
il.Emit(OpCodes.Ret);
/*
* 构造函数 实例化 ModifiedPropertyNames,生成类似于下面的代码
ModifiedPropertyNames = new List();
*/
ConstructorBuilder constructorBuilder = typeBuilderProxy.DefineConstructor(MethodAttributes.Public, CallingConventions.Standard, null);
ILGenerator ilgCtor = constructorBuilder.GetILGenerator();
ilgCtor.Emit(OpCodes.Ldarg_0);//加载当前类
ilgCtor.Emit(OpCodes.Newobj, modifiedPropertyNamesType.GetConstructor(new Type[0]));//实例化对象入栈
ilgCtor.Emit(OpCodes.Stfld, fbModifiedPropertyNames);//设置fbModifiedPropertyNames值,为刚入栈的实例化对象
ilgCtor.Emit(OpCodes.Ret);//返回
//获取被代理对象的所有属性,循环属性进行重写
PropertyInfo[] properties = typeNeedProxy.GetProperties();
foreach (PropertyInfo propertyInfo in properties)
{
string propertyName = propertyInfo.Name;
Type typePepropertyInfo = propertyInfo.PropertyType;
//动态创建字段和属性
FieldBuilder fieldBuilder = typeBuilderProxy.DefineField("_" + propertyName, typePepropertyInfo, FieldAttributes.Private);
PropertyBuilder propertyBuilder = typeBuilderProxy.DefineProperty(propertyName, PropertyAttributes.SpecialName, typePepropertyInfo, null);
//重写属性的Get Set方法
var methodGet = typeBuilderProxy.DefineMethod("get_" + propertyName, GetSetMethodAttributes, typePepropertyInfo, Type.EmptyTypes);
var methodSet = typeBuilderProxy.DefineMethod("set_" + propertyName, GetSetMethodAttributes, null, new Type[] { typePepropertyInfo });
//il of get method
var ilGetMethod = methodGet.GetILGenerator();
ilGetMethod.Emit(OpCodes.Ldarg_0);
ilGetMethod.Emit(OpCodes.Ldfld, fieldBuilder);
ilGetMethod.Emit(OpCodes.Ret);
//il of set method
ILGenerator ilSetMethod = methodSet.GetILGenerator();
var nullLabel = ilSetMethod.DefineLabel();
ilSetMethod.Emit(OpCodes.Ldarg_0);
ilSetMethod.Emit(OpCodes.Ldarg_1);
ilSetMethod.Emit(OpCodes.Stfld, fieldBuilder);
ilSetMethod.Emit(OpCodes.Ldarg_0);
ilSetMethod.Emit(OpCodes.Ldfld, fbModifiedPropertyNames);
ilSetMethod.Emit(OpCodes.Dup);
ilSetMethod.Emit(OpCodes.Brtrue_S, nullLabel);
ilSetMethod.Emit(OpCodes.Pop);
var retLabel = ilSetMethod.DefineLabel();
ilSetMethod.Emit(OpCodes.Br_S, retLabel);
ilSetMethod.MarkLabel(nullLabel);
ilSetMethod.Emit(OpCodes.Ldarg_0);
ilSetMethod.Emit(OpCodes.Ldstr, propertyInfo.Name);
ilSetMethod.Emit(OpCodes.Newobj, typeof(PropertyChangedEventArgs));
ilSetMethod.Emit(OpCodes.Callvirt, pt.GetMethod("Invoke", new Type[] { typeof(object), typeof(PropertyChangedEventArgs) }));
ilSetMethod.Emit(OpCodes.Nop);
il.MarkLabel(retLabel);
ilSetMethod.Emit(OpCodes.Ret);
//设置属性的Get Set方法
propertyBuilder.SetGetMethod(methodGet);
propertyBuilder.SetSetMethod(methodSet);
}
//使用动态类创建类型
Type proxyClassType = typeBuilderProxy.CreateType();
//保存动态创建的程序集
if (isSavaDynamicModule)
assemblyBuilder.Save(DynamicModuleDllName);
//创建类实例
var instance = Activator.CreateInstance(proxyClassType);
return (T)instance;
}
///
/// 获取属性的变更名称,
/// 此处只检测调用了Set方法的属性,不会检测值是否真的有变
///
///
///
public static HashSet GetModifiedProperties(object obj)
{
FieldInfo fieldInfo = obj.GetType().GetField(ModifiedPropertyNamesFieldName);
if (fieldInfo == null) return null;
object value = fieldInfo.GetValue(obj);
return value as HashSet;
}
private static MethodInfo GetGenericMethod(Type type, string methodName)
{
var q = from m in type.GetMethods()
where m.Name == methodName && m.IsGenericMethod
select m;
return q.FirstOrDefault();
}
}
}