public static Type CreateInterfaceProxy(Type interfaceType) { if (null == interfaceType) { throw new ArgumentNullException(nameof(interfaceType)); } if (!interfaceType.IsInterface) { throw new InvalidOperationException($"{interfaceType.FullName} is not an interface"); } var proxyTypeName = _proxyTypeNameResolver(interfaceType, null); if (_proxyTypes.TryGetValue(proxyTypeName, out var proxyType)) { return(proxyType); } lock (_typeLock) { if (_proxyTypes.TryGetValue(proxyTypeName, out proxyType)) { return(proxyType); } var typeBuilder = _moduleBuilder.DefineType(proxyTypeName, TypeAttributes.Public | TypeAttributes.Class | TypeAttributes.Sealed, typeof(object), new[] { interfaceType }); GenericParameterUtils.DefineGenericParameter(interfaceType, typeBuilder); // define default constructor typeBuilder.DefineDefaultConstructor(MethodAttributes.Public); // properties var propertyMethods = new HashSet <string>(); var properties = interfaceType.GetProperties(BindingFlags.Instance | BindingFlags.Public); foreach (var property in properties) { var propertyBuilder = typeBuilder.DefineProperty(property.Name, property.Attributes, property.PropertyType, Type.EmptyTypes); var field = typeBuilder.DefineField($"_{property.Name}", property.PropertyType, FieldAttributes.Private); if (property.CanRead) { var methodBuilder = typeBuilder.DefineMethod(property.GetMethod.Name, InterfaceMethodAttributes, property.GetMethod.CallingConvention, property.GetMethod.ReturnType, property.GetMethod.GetParameters().Select(p => p.ParameterType).ToArray()); var ilGen = methodBuilder.GetILGenerator(); ilGen.Emit(OpCodes.Ldarg_0); ilGen.Emit(OpCodes.Ldfld, field); ilGen.Emit(OpCodes.Ret); typeBuilder.DefineMethodOverride(methodBuilder, property.GetMethod); propertyBuilder.SetGetMethod(methodBuilder); propertyMethods.Add(property.GetMethod.Name); } if (property.CanWrite) { var methodBuilder = typeBuilder.DefineMethod(property.SetMethod.Name, InterfaceMethodAttributes, property.SetMethod.CallingConvention, property.SetMethod.ReturnType, property.SetMethod.GetParameters().Select(p => p.ParameterType).ToArray()); var ilGen = methodBuilder.GetILGenerator(); ilGen.Emit(OpCodes.Ldarg_0); ilGen.Emit(OpCodes.Ldarg_1); ilGen.Emit(OpCodes.Stfld, field); ilGen.Emit(OpCodes.Ret); typeBuilder.DefineMethodOverride(methodBuilder, property.SetMethod); propertyBuilder.SetSetMethod(methodBuilder); propertyMethods.Add(property.SetMethod.Name); } foreach (var customAttributeData in property.CustomAttributes) { propertyBuilder.SetCustomAttribute(DefineCustomAttribute(customAttributeData)); } } // methods var methods = interfaceType.GetMethods(BindingFlags.Instance | BindingFlags.Public); foreach (var method in methods.Where(x => !propertyMethods.Contains(x.Name) && !_ignoredMethods.Contains(x.Name))) { MethodUtils.DefineInterfaceMethod(typeBuilder, method, null); } foreach (var implementedInterface in interfaceType.GetImplementedInterfaces()) { properties = implementedInterface.GetProperties(BindingFlags.Instance | BindingFlags.Public); foreach (var property in properties) { var propertyBuilder = typeBuilder.DefineProperty(property.Name, property.Attributes, property.PropertyType, Type.EmptyTypes); var field = typeBuilder.DefineField($"_{property.Name}", property.PropertyType, FieldAttributes.Private); if (property.CanRead) { var methodBuilder = typeBuilder.DefineMethod(property.GetMethod.Name, InterfaceMethodAttributes, property.GetMethod.CallingConvention, property.GetMethod.ReturnType, property.GetMethod.GetParameters().Select(p => p.ParameterType).ToArray()); var ilGen = methodBuilder.GetILGenerator(); ilGen.Emit(OpCodes.Ldarg_0); ilGen.Emit(OpCodes.Ldfld, field); ilGen.Emit(OpCodes.Ret); typeBuilder.DefineMethodOverride(methodBuilder, property.GetMethod); propertyBuilder.SetGetMethod(methodBuilder); propertyMethods.Add(property.GetMethod.Name); } if (property.CanWrite) { var methodBuilder = typeBuilder.DefineMethod(property.SetMethod.Name, InterfaceMethodAttributes, property.SetMethod.CallingConvention, property.SetMethod.ReturnType, property.SetMethod.GetParameters().Select(p => p.ParameterType).ToArray()); var ilGen = methodBuilder.GetILGenerator(); ilGen.Emit(OpCodes.Ldarg_0); ilGen.Emit(OpCodes.Ldarg_1); ilGen.Emit(OpCodes.Stfld, field); ilGen.Emit(OpCodes.Ret); typeBuilder.DefineMethodOverride(methodBuilder, property.SetMethod); propertyBuilder.SetSetMethod(methodBuilder); propertyMethods.Add(property.SetMethod.Name); } foreach (var customAttributeData in property.CustomAttributes) { propertyBuilder.SetCustomAttribute(DefineCustomAttribute(customAttributeData)); } } methods = implementedInterface.GetMethods(BindingFlags.Instance | BindingFlags.Public); foreach (var method in methods.Where(x => !propertyMethods.Contains(x.Name) && !_ignoredMethods.Contains(x.Name))) { MethodUtils.DefineInterfaceMethod(typeBuilder, method, null); } } proxyType = typeBuilder.CreateType(); _proxyTypes[proxyTypeName] = proxyType; return(proxyType); } }
public static Type CreateClassProxy(Type serviceType, Type implementType) { if (null == serviceType) { throw new ArgumentNullException(nameof(serviceType)); } if (null == implementType) { implementType = serviceType; } if (serviceType.IsSealed || implementType.IsSealed) { throw new InvalidOperationException("the class type is sealed"); } // var proxyTypeName = _proxyTypeNameResolver(serviceType, implementType); if (_proxyTypes.TryGetValue(proxyTypeName, out var proxyType)) { return(proxyType); } lock (_typeLock) { if (_proxyTypes.TryGetValue(proxyTypeName, out proxyType)) { return(proxyType); } var typeBuilder = _moduleBuilder.DefineType(proxyTypeName, TypeAttributes.Public | TypeAttributes.Sealed | TypeAttributes.Class, implementType, Type.EmptyTypes); GenericParameterUtils.DefineGenericParameter(implementType, typeBuilder); var targetField = typeBuilder.DefineField(TargetFieldName, implementType, FieldAttributes.Private); // constructors var constructors = implementType.GetConstructors(); if (constructors.Length > 0) { foreach (var constructor in constructors) { var constructorTypes = constructor.GetParameters().Select(o => o.ParameterType).ToArray(); var constructorBuilder = typeBuilder.DefineConstructor( constructor.Attributes, constructor.CallingConvention, constructorTypes); foreach (var customAttribute in constructor.CustomAttributes) { constructorBuilder.SetCustomAttribute(DefineCustomAttribute(customAttribute)); } var il = constructorBuilder.GetILGenerator(); il.EmitThis(); for (var i = 0; i < constructorTypes.Length; i++) { il.Emit(OpCodes.Ldarg, i + 1); } il.Call(constructor); il.Emit(OpCodes.Nop); il.EmitThis(); il.EmitThis(); il.Emit(OpCodes.Stfld, targetField); il.Emit(OpCodes.Ret); } } else { var constructorBuilder = typeBuilder.DefineConstructor(MethodAttributes.Public, CallingConventions.HasThis, Type.EmptyTypes); var il = constructorBuilder.GetILGenerator(); il.EmitThis(); il.EmitThis(); il.Emit(OpCodes.Stfld, targetField); il.Emit(OpCodes.Ret); } // properties var propertyMethods = new HashSet <string>(); foreach (var property in serviceType.GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)) { if (property.IsVisibleAndVirtual()) { var propertyBuilder = typeBuilder.DefineProperty(property.Name, property.Attributes, property.PropertyType, Type.EmptyTypes); //inherit targetMethod's attribute foreach (var customAttributeData in property.CustomAttributes) { propertyBuilder.SetCustomAttribute(DefineCustomAttribute(customAttributeData)); } if (property.CanRead) { propertyMethods.Add(property.GetMethod.Name); var method = MethodUtils.DefineClassMethod(typeBuilder, property.GetMethod, targetField); propertyBuilder.SetGetMethod(method); } if (property.CanWrite) { propertyMethods.Add(property.SetMethod.Name); var method = MethodUtils.DefineClassMethod(typeBuilder, property.SetMethod, targetField); propertyBuilder.SetSetMethod(method); } } } // methods var methods = serviceType.GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance) .Where(m => m.IsVirtual && !m.IsFinal && m.IsVisible() && !propertyMethods.Contains(m.Name) && !_ignoredMethods.Contains(m.Name)) .ToArray(); foreach (var method in methods) { MethodUtils.DefineClassMethod(typeBuilder, method, targetField); } proxyType = typeBuilder.CreateType(); _proxyTypes[proxyTypeName] = proxyType; return(proxyType); } }
public static MethodBuilder DefineClassMethod(TypeBuilder typeBuilder, MethodInfo method, FieldBuilder targetField) { var methodParameterTypes = method.GetParameters() .Select(p => p.ParameterType) .ToArray(); var methodAttributes = OverrideMethodAttributes; if (method.Attributes.HasFlag(MethodAttributes.Public)) { methodAttributes |= MethodAttributes.Public; } if (method.Attributes.HasFlag(MethodAttributes.Family)) { methodAttributes |= MethodAttributes.Family; } if (method.Attributes.HasFlag(MethodAttributes.FamORAssem)) { methodAttributes |= MethodAttributes.FamORAssem; } var methodBuilder = typeBuilder.DefineMethod(method.Name, methodAttributes, method.CallingConvention, method.ReturnType, methodParameterTypes ); GenericParameterUtils.DefineGenericParameter(method, methodBuilder); foreach (var customAttributeData in method.CustomAttributes) { methodBuilder.SetCustomAttribute(DefineCustomAttribute(customAttributeData)); } var il = methodBuilder.GetILGenerator(); var localReturnValue = il.DeclareReturnValue(method.ReturnType); var localCurrentMethod = il.DeclareLocal(typeof(MethodInfo)); var localMethodBase = il.DeclareLocal(typeof(MethodInfo)); var localParameters = il.DeclareLocal(typeof(object[])); // var currentMethod = MethodBase.GetCurrentMethod(); il.Call(MethodInvokeHelper.GetCurrentMethod); il.EmitConvertToType(typeof(MethodBase), typeof(MethodInfo)); il.Emit(OpCodes.Stloc, localCurrentMethod); var targetMethod = targetField?.FieldType.GetMethodBySignature(method); if (null != targetMethod) { il.EmitMethod(methodBuilder.IsGenericMethod ? targetMethod.MakeGenericMethod(methodBuilder.GetGenericArguments()) : targetMethod); } else { il.EmitNull(); } il.Emit(OpCodes.Stloc, localMethodBase); // var parameters = new[] {a, b, c}; il.Emit(OpCodes.Ldc_I4, methodParameterTypes.Length); il.Emit(OpCodes.Newarr, typeof(object)); if (methodParameterTypes.Length > 0) { for (var i = 0; i < methodParameterTypes.Length; i++) { il.Emit(OpCodes.Dup); il.Emit(OpCodes.Ldc_I4, i); il.Emit(OpCodes.Ldarg, i + 1); if (methodParameterTypes[i].IsValueType) { il.Emit(OpCodes.Box, methodParameterTypes[i].UnderlyingSystemType); } il.Emit(OpCodes.Stelem_Ref); } } il.Emit(OpCodes.Stloc, localParameters); // var invocation = new MethodInvocation(method, methodBase, this, this, parameters); var localAspectInvocation = il.DeclareLocal(typeof(AspectInvocation)); il.Emit(OpCodes.Ldloc, localCurrentMethod); il.Emit(OpCodes.Ldloc, localMethodBase); il.EmitThis(); il.EmitThis(); if (null != targetField) { il.Emit(OpCodes.Ldfld, targetField); } il.Emit(OpCodes.Ldloc, localParameters); il.New(MethodInvokeHelper.AspectInvocationConstructor); il.Emit(OpCodes.Stloc, localAspectInvocation); // AspectDelegate.Invoke(invocation); il.Emit(OpCodes.Ldloc, localAspectInvocation); il.Call(MethodInvokeHelper.InvokeAspectDelegateMethod); if (method.ReturnType != typeof(void)) { // load return value il.Emit(OpCodes.Ldloc, localAspectInvocation); il.EmitCall(OpCodes.Callvirt, MethodInvokeHelper.GetInvocationReturnValueMethod, Type.EmptyTypes); if (method.ReturnType.IsValueType) { il.EmitCastToType(typeof(object), method.ReturnType); } il.Emit(OpCodes.Stloc, localReturnValue); il.Emit(OpCodes.Ldloc, localReturnValue); } il.Emit(OpCodes.Ret); return(methodBuilder); }
public static Type CreateInterfaceProxy(Type interfaceType, Type implementType) { if (null == interfaceType) { throw new ArgumentNullException(nameof(interfaceType)); } if (!interfaceType.IsInterface) { throw new InvalidOperationException($"{interfaceType.FullName} is not an interface"); } if (null == implementType) { return(CreateInterfaceProxy(interfaceType)); } if (implementType.IsSealed) { throw new InvalidOperationException("the implementType is sealed"); } var proxyTypeName = _proxyTypeNameResolver(interfaceType, implementType); var type = _proxyTypes.GetOrAdd(proxyTypeName, name => { var typeBuilder = _moduleBuilder.DefineType(proxyTypeName, implementType.Attributes, implementType, new[] { interfaceType }); GenericParameterUtils.DefineGenericParameter(interfaceType, typeBuilder); var targetField = typeBuilder.DefineField(TargetFieldName, implementType, FieldAttributes.Private); // constructors foreach (var constructor in implementType.GetConstructors()) { var constructorTypes = constructor.GetParameters().Select(o => o.ParameterType).ToArray(); var constructorBuilder = typeBuilder.DefineConstructor( constructor.Attributes, constructor.CallingConvention, constructorTypes); foreach (var customAttribute in constructor.CustomAttributes) { constructorBuilder.SetCustomAttribute(DefineCustomAttribute(customAttribute)); } var il = constructorBuilder.GetILGenerator(); il.EmitThis(); for (var i = 0; i < constructorTypes.Length; i++) { il.Emit(OpCodes.Ldarg, i + 1); } il.Call(constructor); il.EmitThis(); il.EmitThis(); il.Emit(OpCodes.Stfld, targetField); il.Emit(OpCodes.Nop); il.Emit(OpCodes.Ret); } // properties var propertyMethods = new HashSet <string>(); var properties = interfaceType.GetProperties(BindingFlags.Instance | BindingFlags.Public); foreach (var property in properties) { var propertyBuilder = typeBuilder.DefineProperty(property.Name, property.Attributes, property.PropertyType, Type.EmptyTypes); if (property.CanRead) { var methodBuilder = MethodUtils.DefineInterfaceMethod(typeBuilder, property.GetMethod, targetField); typeBuilder.DefineMethodOverride(methodBuilder, property.GetMethod); propertyBuilder.SetGetMethod(methodBuilder); propertyMethods.Add(property.GetMethod.Name); } if (property.CanWrite) { var methodBuilder = MethodUtils.DefineInterfaceMethod(typeBuilder, property.SetMethod, targetField); typeBuilder.DefineMethodOverride(methodBuilder, property.SetMethod); propertyBuilder.SetSetMethod(methodBuilder); propertyMethods.Add(property.SetMethod.Name); } foreach (var customAttributeData in property.CustomAttributes) { propertyBuilder.SetCustomAttribute(DefineCustomAttribute(customAttributeData)); } } // var methods = interfaceType.GetMethods(BindingFlags.Instance | BindingFlags.Public); foreach (var method in methods) { if (propertyMethods.Contains(method.Name) || _ignoredMethods.Contains(method.Name)) { continue; } MethodUtils.DefineInterfaceMethod(typeBuilder, method, targetField); } foreach (var implementedInterface in interfaceType.GetImplementedInterfaces()) { properties = implementedInterface.GetProperties(BindingFlags.Instance | BindingFlags.Public); foreach (var property in properties) { var propertyBuilder = typeBuilder.DefineProperty(property.Name, property.Attributes, property.PropertyType, Type.EmptyTypes); var field = typeBuilder.DefineField($"_{property.Name}", property.PropertyType, FieldAttributes.Private); if (property.CanRead) { var methodBuilder = typeBuilder.DefineMethod(property.GetMethod.Name, InterfaceMethodAttributes, property.GetMethod.CallingConvention, property.GetMethod.ReturnType, property.GetMethod.GetParameters().Select(p => p.ParameterType).ToArray()); var ilGen = methodBuilder.GetILGenerator(); ilGen.Emit(OpCodes.Ldarg_0); ilGen.Emit(OpCodes.Ldfld, field); ilGen.Emit(OpCodes.Ret); typeBuilder.DefineMethodOverride(methodBuilder, property.GetMethod); propertyBuilder.SetGetMethod(methodBuilder); propertyMethods.Add(property.GetMethod.Name); } if (property.CanWrite) { var methodBuilder = typeBuilder.DefineMethod(property.SetMethod.Name, InterfaceMethodAttributes, property.SetMethod.CallingConvention, property.SetMethod.ReturnType, property.SetMethod.GetParameters().Select(p => p.ParameterType).ToArray()); var ilGen = methodBuilder.GetILGenerator(); ilGen.Emit(OpCodes.Ldarg_0); ilGen.Emit(OpCodes.Ldarg_1); ilGen.Emit(OpCodes.Stfld, field); ilGen.Emit(OpCodes.Ret); typeBuilder.DefineMethodOverride(methodBuilder, property.SetMethod); propertyBuilder.SetSetMethod(methodBuilder); propertyMethods.Add(property.SetMethod.Name); } foreach (var customAttributeData in property.CustomAttributes) { propertyBuilder.SetCustomAttribute(DefineCustomAttribute(customAttributeData)); } } methods = implementedInterface.GetMethods(BindingFlags.Instance | BindingFlags.Public); foreach (var method in methods.Where(x => !propertyMethods.Contains(x.Name) && !_ignoredMethods.Contains(x.Name))) { MethodUtils.DefineInterfaceMethod(typeBuilder, method, null); } } return(typeBuilder.CreateType()); }); return(type); }