using System.Reflection; using System.Reflection.Emit; namespace WCS.Core; /// /// 动态创建接口实例 /// /// 接口 /// 基类 public static class Generator where TBase : IProtocolProxy { private const MethodAttributes METHOD_ATTRIBUTES = MethodAttributes.Public | MethodAttributes.NewSlot | MethodAttributes.Virtual | MethodAttributes.Final | MethodAttributes.HideBySig; private static readonly TypeBuilder tb; private static readonly Type Type; static Generator() { if (!typeof(T).IsInterface) throw new Exception("T必须是interface"); if (!typeof(TBase).IsClass) throw new Exception("TBase必须是class"); var myAssemblyName = new AssemblyName(); myAssemblyName.Name = typeof(T).Name + "_Generate"; var myAssembly = AssemblyBuilder.DefineDynamicAssembly(myAssemblyName, AssemblyBuilderAccess.RunAndCollect); //AssemblyBuilder myAssembly = AssemblyBuilder.DefineDynamicAssembly(myAssemblyName, AssemblyBuilderAccess.RunAndSave); var myModule = myAssembly.DefineDynamicModule("Main"); tb = myModule.DefineType(typeof(T).Name + "_Generate", TypeAttributes.Public, typeof(TBase), new[] { typeof(T) }); InitConstructors(); InitMethods(); InitProperties(); InitEvents(); try { Type = tb.CreateTypeInfo().AsType(); //.CreateType(); } catch (Exception ex) { } //myAssembly.Save(typeof(T).Name + ".dll"); } private static void InitConstructors() { foreach (var cons in typeof(TBase).GetConstructors()) { var pTypes = cons.GetParameters().Select(v => v.ParameterType).ToArray(); var build = tb.DefineConstructor(cons.Attributes, CallingConventions.Standard, pTypes); for (var i = 0; i < pTypes.Length; i++) build.DefineParameter(i + 1, ParameterAttributes.In, "p" + i); var il = build.GetILGenerator(); il.Emit(OpCodes.Ldarg_0); for (var i = 0; i < pTypes.Length; i++) il.Emit(OpCodes.Ldarg, i + 1); il.Emit(OpCodes.Call, cons); //il.Emit(OpCodes.Pop); il.Emit(OpCodes.Ret); } } private static void InitMethods() { var ms = GetInterfaces().SelectMany(v => v.GetMethods()).ToArray(); ms = ms.Where(v => !v.IsSpecialName).ToArray(); foreach (var m in ms) GenerateMethod(m); } private static void InitProperties() { var ps = GetInterfaces().SelectMany(v => v.GetProperties()); ps = GetMembers().OfType(); foreach (var p in ps) { if (typeof(TBase).GetProperty(p.Name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) != null) continue; var pTypes = p.GetIndexParameters().Select(v => v.ParameterType).ToArray(); var pb = tb.DefineProperty(p.Name, p.Attributes, p.PropertyType, pTypes); if (p.CanRead) { if (pTypes.Length > 0) { //索引器 var mb = GenerateIndexer(p.GetGetMethod()); pb.SetGetMethod(mb); } else { var mb = GenerateProperty(p.GetGetMethod()); pb.SetGetMethod(mb); } } if (p.CanWrite) { if (pTypes.Length > 0) { var mb = GenerateIndexer(p.GetSetMethod()); pb.SetSetMethod(mb); } else { var mb = GenerateProperty(p.GetSetMethod()); pb.SetSetMethod(mb); } } } } private static void InitEvents() { var evts = GetInterfaces().SelectMany(v => v.GetEvents()); foreach (var evt in evts) { var eb = tb.DefineEvent(evt.Name, evt.Attributes, evt.EventHandlerType); var add = GenerateEventEnabled(evt, evt.GetAddMethod()); eb.SetAddOnMethod(add); var remove = GenerateEventEnabled(evt, evt.GetRemoveMethod()); eb.SetRemoveOnMethod(remove); } } private static MethodBuilder GenerateMethod(MethodInfo m) { var pTypes = m.GetParameters().Select(v => v.ParameterType).ToArray(); var mb = tb.DefineMethod(m.Name, METHOD_ATTRIBUTES, CallingConventions.Standard, m.ReturnType, pTypes); var ilGen = mb.GetILGenerator(); ilGen.DeclareLocal(typeof(object[])); //声明object数组变量 #region 参数准备 ilGen.Emit(OpCodes.Ldarg_0); //this ilGen.Emit(OpCodes.Ldstr, m.Name); //string name ilGen.Emit(OpCodes.Ldc_I4_S, pTypes.Length); //数组长度 ilGen.Emit(OpCodes.Newarr, typeof(object)); //数组 ilGen.Emit(OpCodes.Stloc_0); for (var i = 0; i < pTypes.Length; i++) { ilGen.Emit(OpCodes.Ldloc_0); ilGen.Emit(OpCodes.Ldc_I4_S, i); ilGen.Emit(OpCodes.Ldarg_S, 1 + i); ilGen.Emit(OpCodes.Box, pTypes[i]); ilGen.Emit(OpCodes.Stelem_Ref); } #endregion ilGen.Emit(OpCodes.Ldloc_0); if (m.ReturnType != typeof(void)) { var mi = typeof(TBase).GetMethod("CallReturn", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public); mi = mi.MakeGenericMethod(m.ReturnType); ilGen.Emit(OpCodes.Call, mi); var local = ilGen.DeclareLocal(m.ReturnType); ilGen.Emit(OpCodes.Stloc_1, local); ilGen.Emit(OpCodes.Ldloc_1, local); } else { var mi = typeof(TBase).GetMethod("CallVoid", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public); ilGen.Emit(OpCodes.Call, mi); } ilGen.Emit(OpCodes.Ret); return mb; } private static MethodBuilder GenerateProperty(MethodInfo m) { var pTypes = m.GetParameters().Select(v => v.ParameterType).ToArray(); var mb = tb.DefineMethod(m.Name, METHOD_ATTRIBUTES, CallingConventions.Standard, m.ReturnType, pTypes); var ilGen = mb.GetILGenerator(); #region 参数准备 ilGen.Emit(OpCodes.Ldarg_0); //this ilGen.Emit(OpCodes.Ldstr, m.Name.Replace("set_", "").Replace("get_", "")); //string name #endregion if (m.Name.StartsWith("set_")) { ilGen.Emit(OpCodes.Ldarg_1); //value 准备参数 var mi = typeof(TBase).GetMethod("Set", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); mi = mi.MakeGenericMethod(pTypes); ilGen.Emit(OpCodes.Call, mi); //调用基类方法 //ilGen.Emit(OpCodes.Pop); } else { var mi = typeof(TBase).GetMethod("Get", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); mi = mi.MakeGenericMethod(m.ReturnType); ilGen.Emit(OpCodes.Call, mi); //调用方法 #region 返回值 var local = ilGen.DeclareLocal(m.ReturnType); ilGen.Emit(OpCodes.Stloc_0, local); ilGen.Emit(OpCodes.Ldloc_0, local); #endregion } ilGen.Emit(OpCodes.Ret); //return return mb; } private static MethodBuilder GenerateIndexer(MethodInfo m) { var pTypes = m.GetParameters().Select(v => v.ParameterType).ToArray(); var mb = tb.DefineMethod(m.Name, METHOD_ATTRIBUTES, CallingConventions.Standard, m.ReturnType, pTypes); var ilGen = mb.GetILGenerator(); #region 参数准备 ilGen.DeclareLocal(typeof(object[])); //声明object数组变量 ilGen.Emit(OpCodes.Ldarg_0); //this ilGen.Emit(OpCodes.Ldc_I4_S, pTypes.Length); //数组长度 ilGen.Emit(OpCodes.Newarr, typeof(object)); //数组 ilGen.Emit(OpCodes.Stloc_0); var i = 0; for (i = 0; i < pTypes.Length; i++) { ilGen.Emit(OpCodes.Ldloc_0); ilGen.Emit(OpCodes.Ldc_I4_S, i); ilGen.Emit(OpCodes.Ldarg_S, 1 + i); ilGen.Emit(OpCodes.Box, pTypes[i]); ilGen.Emit(OpCodes.Stelem_Ref); } #endregion ilGen.Emit(OpCodes.Ldloc_0); if (m.Name.StartsWith("set")) { //ilGen.Emit(OpCodes.Ldarg_S, 1 + i);//value 准备参数 var mi = typeof(TBase).GetMethod("SetItem", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); ilGen.Emit(OpCodes.Call, mi); //调用基类方法 //ilGen.Emit(OpCodes.Pop); } else { var mi = typeof(TBase).GetMethod("GetItem", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); mi = mi.MakeGenericMethod(m.ReturnType); ilGen.Emit(OpCodes.Call, mi); //调用方法 #region 返回值 var local = ilGen.DeclareLocal(m.ReturnType); ilGen.Emit(OpCodes.Stloc_1, local); ilGen.Emit(OpCodes.Ldloc_1, local); #endregion } ilGen.Emit(OpCodes.Ret); //return return mb; } private static MethodBuilder GenerateEventEnabled(EventInfo evt, MethodInfo m) { var add = m.Name.StartsWith("add_"); var n = m.DeclaringType.Name; var pTypes = m.GetParameters().Select(v => v.ParameterType).ToArray(); var mb = tb.DefineMethod(m.Name, METHOD_ATTRIBUTES, CallingConventions.Standard, m.ReturnType, pTypes); var ilGen = mb.GetILGenerator(); //ilGen.DeclareLocal(typeof(EventInfo));//声明字符串变量 //ilGen.DeclareLocal(typeof(Delegate)); //value Delegate //ilGen.Emit(OpCodes.Ldstr, evt.Name);//string evtName 字符串值 //ilGen.Emit(OpCodes.Stloc_0);//保存至变量 //ilGen.Emit(OpCodes.Ldarg_1);//Delegate dlg //ilGen.Emit(OpCodes.Stloc_1);//保存至变量 #region 参数准备 ilGen.Emit(OpCodes.Ldarg_0); ilGen.Emit(OpCodes.Ldstr, evt.Name); ilGen.Emit(OpCodes.Ldarg_1); #endregion var mname = add ? "AddEvent" : "RemoveEvent"; ilGen.Emit(OpCodes.Call, typeof(TBase).GetMethod(mname, BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public)); ilGen.Emit(OpCodes.Ret); return mb; } private static Type[] GetInterfaces() { var tInterface = typeof(T); var ts = tInterface.GetInterfaces().ToList(); ts.Add(tInterface); return ts.ToArray(); } private static MemberInfo[] GetMembers() { var members = GetInterfaces().SelectMany(v => v.GetMembers()).Distinct().ToArray(); return members; } public static T Create(params object[] args) { return (T)Activator.CreateInstance(Type, args); } public static Type GetGenerateType() { return Type; } }