Unity Framework 中的一个类, 我也是醉了
// Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information. using System; using System.Collections.Generic; using System.Linq; using System.Reflection; using System.Reflection.Emit; namespace Microsoft.Practices.Unity.InterceptionExtension { internal class InterfaceImplementation { private readonly TypeBuilder typeBuilder; private readonly Type @interface; private readonly Type targetInterface; private readonly GenericParameterMapper genericParameterMapper; private readonly FieldBuilder proxyInterceptionPipelineField; private readonly bool explicitImplementation; private readonly FieldBuilder targetField; public InterfaceImplementation( TypeBuilder typeBuilder, Type @interface, FieldBuilder proxyInterceptionPipelineField, bool explicitImplementation) : this(typeBuilder, @interface, proxyInterceptionPipelineField, explicitImplementation, null) { } public InterfaceImplementation( TypeBuilder typeBuilder, Type @interface, FieldBuilder proxyInterceptionPipelineField, bool explicitImplementation, FieldBuilder targetField) : this(typeBuilder, @interface, GenericParameterMapper.DefaultMapper, proxyInterceptionPipelineField, explicitImplementation, targetField) { } public InterfaceImplementation( TypeBuilder typeBuilder, Type @interface, GenericParameterMapper genericParameterMapper, FieldBuilder proxyInterceptionPipelineField, bool explicitImplementation, FieldBuilder targetField) { this.typeBuilder = typeBuilder; this.@interface = @interface; this.genericParameterMapper = genericParameterMapper; this.proxyInterceptionPipelineField = proxyInterceptionPipelineField; this.explicitImplementation = explicitImplementation; this.targetField = targetField; if (@interface.IsGenericType) { // when the @interface is generic we need to get references to its methods though it // in this case, the targetInterface is a constructed version using the generic type parameters // from the generated type generate type var definition = @interface.GetGenericTypeDefinition(); var mappedParameters = definition.GetGenericArguments().Select(t => genericParameterMapper.Map(t)).ToArray(); this.targetInterface = definition.MakeGenericType(mappedParameters); } else { this.targetInterface = @interface; } } public int Implement(HashSet<Type> implementedInterfaces, int memberCount) { if (implementedInterfaces.Contains(this.@interface)) { return memberCount; } implementedInterfaces.Add(this.@interface); typeBuilder.AddInterfaceImplementation(this.@interface); foreach (MethodInfo method in MethodsToIntercept()) { OverrideMethod(method, memberCount++); } foreach (PropertyInfo property in PropertiesToIntercept()) { OverrideProperty(property, memberCount++); } foreach (EventInfo @event in EventsToIntercept()) { OverrideEvent(@event, memberCount++); } foreach (var @extendedInterface in [email protected]()) { memberCount = new InterfaceImplementation( this.typeBuilder, @extendedInterface, new GenericParameterMapper(@extendedInterface, this.genericParameterMapper), this.proxyInterceptionPipelineField, this.explicitImplementation, this.targetField) .Implement(implementedInterfaces, memberCount); } return memberCount; } private IEnumerable<MethodInfo> MethodsToIntercept() { foreach (MethodInfo method in [email protected]( BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)) { if (!method.IsSpecialName) { yield return method; } } } private void OverrideMethod(MethodInfo method, int methodNum) { new InterfaceMethodOverride( this.typeBuilder, this.proxyInterceptionPipelineField, this.targetField, method, this.targetInterface, this.genericParameterMapper, this.explicitImplementation, methodNum) .AddMethod(); } private IEnumerable<PropertyInfo> PropertiesToIntercept() { return [email protected]( BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); } private void OverrideProperty(PropertyInfo property, int count) { MethodBuilder getMethod = OverridePropertyMethod(property.GetGetMethod(), count); MethodBuilder setMethod = OverridePropertyMethod(property.GetSetMethod(), count); AddPropertyDefinition(property, getMethod, setMethod); } private void AddPropertyDefinition(PropertyInfo property, MethodBuilder getMethod, MethodBuilder setMethod) { PropertyBuilder newProperty = this.typeBuilder.DefineProperty( property.Name, property.Attributes, property.PropertyType, property.GetIndexParameters().Select(param => param.ParameterType).ToArray()); if (getMethod != null) { newProperty.SetGetMethod(getMethod); } if (setMethod != null) { newProperty.SetSetMethod(setMethod); } } private MethodBuilder OverridePropertyMethod(MethodInfo method, int count) { return method == null ? null : new InterfaceMethodOverride( this.typeBuilder, this.proxyInterceptionPipelineField, this.targetField, method, this.targetInterface, this.genericParameterMapper, this.explicitImplementation, count) .AddMethod(); } private IEnumerable<EventInfo> EventsToIntercept() { return [email protected]( BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); } private void OverrideEvent(EventInfo @event, int count) { MethodBuilder addMethod = OverrideEventMethod(@event.GetAddMethod(), count); MethodBuilder removeMethod = OverrideEventMethod(@event.GetRemoveMethod(), count); AddEventDefinition(@event, addMethod, removeMethod); } private void AddEventDefinition(EventInfo @event, MethodBuilder addMethod, MethodBuilder removeMethod) { EventBuilder newEvent = this.typeBuilder.DefineEvent(@event.Name, @event.Attributes, @event.EventHandlerType); if (addMethod != null) { newEvent.SetAddOnMethod(addMethod); } if (removeMethod != null) { newEvent.SetRemoveOnMethod(removeMethod); } } private MethodBuilder OverrideEventMethod(MethodInfo method, int count) { return method == null ? null : new InterfaceMethodOverride( this.typeBuilder, this.proxyInterceptionPipelineField, this.targetField, method, this.targetInterface, this.genericParameterMapper, this.explicitImplementation, count) .AddMethod(); } } }
另一个类
// Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information. using System; using System.Collections.Generic; using System.Globalization; using System.Linq; using System.Reflection; using System.Reflection.Emit; using Microsoft.Practices.Unity.InterceptionExtension.Properties; using Microsoft.Practices.Unity.Utility; namespace Microsoft.Practices.Unity.InterceptionExtension { /// <summary> /// Represents the implementation of an interface method. /// </summary> public class InterfaceMethodOverride { private static readonly MethodInfo BuildAdditionalInterfaceNonImplementedExceptionMethod = StaticReflection.GetMethodInfo(() => InterfaceMethodOverride.BuildAdditionalInterfaceNonImplementedException()); private const MethodAttributes ImplicitImplementationAttributes = MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.Final | MethodAttributes.HideBySig | MethodAttributes.NewSlot; private const MethodAttributes ExplicitImplementationAttributes = MethodAttributes.Private | MethodAttributes.Virtual | MethodAttributes.Final | MethodAttributes.HideBySig | MethodAttributes.NewSlot; private readonly TypeBuilder typeBuilder; private readonly MethodInfo methodToOverride; private readonly ParameterInfo[] methodParameters; private readonly FieldBuilder proxyInterceptionPipelineField; private readonly bool explicitImplementation; private readonly FieldBuilder targetField; private readonly Type targetInterface; private readonly GenericParameterMapper targetInterfaceParameterMapper; private readonly int overrideCount; internal InterfaceMethodOverride( TypeBuilder typeBuilder, FieldBuilder proxyInterceptionPipelineField, FieldBuilder targetField, MethodInfo methodToOverride, Type targetInterface, GenericParameterMapper targetInterfaceParameterMapper, bool explicitImplementation, int overrideCount) { this.typeBuilder = typeBuilder; this.proxyInterceptionPipelineField = proxyInterceptionPipelineField; this.explicitImplementation = explicitImplementation; this.targetField = targetField; this.methodToOverride = methodToOverride; this.targetInterface = targetInterface; this.targetInterfaceParameterMapper = targetInterfaceParameterMapper; this.methodParameters = methodToOverride.GetParameters(); this.overrideCount = overrideCount; } internal MethodBuilder AddMethod() { MethodBuilder delegateMethod = CreateDelegateImplementation(); return CreateMethodOverride(delegateMethod); } private string CreateMethodName(string purpose) { return "<" + methodToOverride.Name + "_" + purpose + ">__" + overrideCount.ToString(CultureInfo.InvariantCulture); } private static readonly OpCode[] LoadArgsOpcodes = { OpCodes.Ldarg_1, OpCodes.Ldarg_2, OpCodes.Ldarg_3 }; private static void EmitLoadArgument(ILGenerator il, int argumentNumber) { if (argumentNumber < LoadArgsOpcodes.Length) { il.Emit(LoadArgsOpcodes[argumentNumber]); } else { il.Emit(OpCodes.Ldarg, argumentNumber + 1); } } private static readonly OpCode[] LoadConstOpCodes = { OpCodes.Ldc_I4_0, OpCodes.Ldc_I4_1, OpCodes.Ldc_I4_2, OpCodes.Ldc_I4_3, OpCodes.Ldc_I4_4, OpCodes.Ldc_I4_5, OpCodes.Ldc_I4_6, OpCodes.Ldc_I4_7, OpCodes.Ldc_I4_8, }; private static void EmitLoadConstant(ILGenerator il, int i) { if (i < LoadConstOpCodes.Length) { il.Emit(LoadConstOpCodes[i]); } else { il.Emit(OpCodes.Ldc_I4, i); } } private static void EmitBox(ILGenerator il, Type typeOnStack) { if (typeOnStack.IsValueType || typeOnStack.IsGenericParameter) { il.Emit(OpCodes.Box, typeOnStack); } } private static void EmitUnboxOrCast(ILGenerator il, Type targetType) { if (targetType.IsValueType || targetType.IsGenericParameter) { il.Emit(OpCodes.Unbox_Any, targetType); } else { il.Emit(OpCodes.Castclass, targetType); } } private MethodBuilder CreateDelegateImplementation() { string methodName = CreateMethodName("DelegateImplementation"); MethodBuilder methodBuilder = typeBuilder.DefineMethod(methodName, MethodAttributes.Private | MethodAttributes.HideBySig); List<LocalBuilder> outOrRefLocals = new List<LocalBuilder>(); var paramMapper = new MethodOverrideParameterMapper(methodToOverride); paramMapper.SetupParameters(methodBuilder, this.targetInterfaceParameterMapper); methodBuilder.SetReturnType(typeof(IMethodReturn)); // Adding parameters methodBuilder.SetParameters(typeof(IMethodInvocation), typeof(GetNextInterceptionBehaviorDelegate)); // Parameter methodBuilder.DefineParameter(1, ParameterAttributes.None, "inputs"); // Parameter methodBuilder.DefineParameter(2, ParameterAttributes.None, "getNext"); methodBuilder.SetCustomAttribute(new CustomAttributeBuilder(CompilerGeneratedAttributeMethods.CompilerGeneratedAttribute, new object[0])); ILGenerator il = methodBuilder.GetILGenerator(); if (this.targetField != null) { // forwarding implementation Label done = il.DefineLabel(); LocalBuilder ex = il.DeclareLocal(typeof(Exception)); LocalBuilder baseReturn = null; LocalBuilder parameters = null; if (MethodHasReturnValue) { baseReturn = il.DeclareLocal(paramMapper.GetReturnType()); } LocalBuilder retval = il.DeclareLocal(typeof(IMethodReturn)); il.BeginExceptionBlock(); // Call the target method il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Ldfld, targetField); if (methodParameters.Length > 0) { parameters = il.DeclareLocal(typeof(IParameterCollection)); il.Emit(OpCodes.Ldarg_1); il.EmitCall(OpCodes.Callvirt, IMethodInvocationMethods.GetArguments, null); il.Emit(OpCodes.Stloc, parameters); for (int i = 0; i < methodParameters.Length; ++i) { il.Emit(OpCodes.Ldloc, parameters); EmitLoadConstant(il, i); il.EmitCall(OpCodes.Callvirt, IListMethods.GetItem, null); Type parameterType = paramMapper.GetParameterType(methodParameters[i].ParameterType); if (parameterType.IsByRef) { Type elementType = parameterType.GetElementType(); LocalBuilder refShadowLocal = il.DeclareLocal(elementType); outOrRefLocals.Add(refShadowLocal); EmitUnboxOrCast(il, elementType); il.Emit(OpCodes.Stloc, refShadowLocal); il.Emit(OpCodes.Ldloca, refShadowLocal); } else { EmitUnboxOrCast(il, parameterType); } } } MethodInfo callTarget = methodToOverride; if (callTarget.IsGenericMethod) { callTarget = methodToOverride.MakeGenericMethod(paramMapper.GenericMethodParameters); } il.Emit(OpCodes.Callvirt, callTarget); if (MethodHasReturnValue) { il.Emit(OpCodes.Stloc, baseReturn); } // Generate the return value il.Emit(OpCodes.Ldarg_1); if (MethodHasReturnValue) { il.Emit(OpCodes.Ldloc, baseReturn); EmitBox(il, paramMapper.GetReturnType()); } else { il.Emit(OpCodes.Ldnull); } EmitLoadConstant(il, methodParameters.Length); il.Emit(OpCodes.Newarr, typeof(object)); if (methodParameters.Length > 0) { LocalBuilder outputArguments = il.DeclareLocal(typeof(object[])); il.Emit(OpCodes.Stloc, outputArguments); int outputArgNum = 0; for (int i = 0; i < methodParameters.Length; ++i) { il.Emit(OpCodes.Ldloc, outputArguments); EmitLoadConstant(il, i); Type parameterType = paramMapper.GetParameterType(methodParameters[i].ParameterType); if (parameterType.IsByRef) { parameterType = parameterType.GetElementType(); il.Emit(OpCodes.Ldloc, outOrRefLocals[outputArgNum++]); EmitBox(il, parameterType); } else { il.Emit(OpCodes.Ldloc, parameters); EmitLoadConstant(il, i); il.Emit(OpCodes.Callvirt, IListMethods.GetItem); } il.Emit(OpCodes.Stelem_Ref); } il.Emit(OpCodes.Ldloc, outputArguments); } il.Emit(OpCodes.Callvirt, IMethodInvocationMethods.CreateReturn); il.Emit(OpCodes.Stloc, retval); il.BeginCatchBlock(typeof(Exception)); il.Emit(OpCodes.Stloc, ex); // Create an exception return il.Emit(OpCodes.Ldarg_1); il.Emit(OpCodes.Ldloc, ex); il.EmitCall(OpCodes.Callvirt, IMethodInvocationMethods.CreateExceptionMethodReturn, null); il.Emit(OpCodes.Stloc, retval); il.EndExceptionBlock(); il.MarkLabel(done); il.Emit(OpCodes.Ldloc, retval); il.Emit(OpCodes.Ret); } else { // exception-throwing implementation il.Emit(OpCodes.Ldarg_1); il.EmitCall(OpCodes.Call, BuildAdditionalInterfaceNonImplementedExceptionMethod, null); il.EmitCall(OpCodes.Callvirt, IMethodInvocationMethods.CreateExceptionMethodReturn, null); il.Emit(OpCodes.Ret); } return methodBuilder; } private MethodBuilder CreateMethodOverride(MethodBuilder delegateMethod) { string methodName = this.explicitImplementation ? methodToOverride.DeclaringType.Name + "." + methodToOverride.Name : methodToOverride.Name; MethodBuilder methodBuilder = typeBuilder.DefineMethod( methodName, this.explicitImplementation ? ExplicitImplementationAttributes : ImplicitImplementationAttributes); var paramMapper = new MethodOverrideParameterMapper(methodToOverride); paramMapper.SetupParameters(methodBuilder, this.targetInterfaceParameterMapper); methodBuilder.SetReturnType(paramMapper.GetReturnType()); methodBuilder.SetParameters(methodParameters.Select(pi => paramMapper.GetParameterType(pi.ParameterType)).ToArray()); if (this.explicitImplementation) { this.typeBuilder.DefineMethodOverride(methodBuilder, this.methodToOverride); } int paramNum = 1; foreach (ParameterInfo pi in methodParameters) { methodBuilder.DefineParameter(paramNum++, pi.Attributes, pi.Name); } ILGenerator il = methodBuilder.GetILGenerator(); LocalBuilder methodReturn = il.DeclareLocal(typeof(IMethodReturn)); LocalBuilder ex = il.DeclareLocal(typeof(Exception)); LocalBuilder parameterArray = il.DeclareLocal(typeof(object[])); LocalBuilder inputs = il.DeclareLocal(typeof(VirtualMethodInvocation)); // Create instance of VirtualMethodInvocation il.Emit(OpCodes.Ldarg_0); // target object // If we have a targetField, that means we're building a proxy and // should use it as the target object. If we don't, we're building // a type interceptor and should leave the this pointer as the // target. if (targetField != null) { il.Emit(OpCodes.Ldfld, targetField); } // If we have a generic method, we want to make sure we're using the open constructed generic method // so when a closed generic version of the method is invoked the actual type parameters are used il.Emit( OpCodes.Ldtoken, methodToOverride.IsGenericMethodDefinition ? methodToOverride.MakeGenericMethod(paramMapper.GenericMethodParameters) : methodToOverride); if (methodToOverride.DeclaringType.IsGenericType) { // if the declaring type is generic, we need to get the method from the target type il.Emit(OpCodes.Ldtoken, targetInterface); il.Emit(OpCodes.Call, MethodBaseMethods.GetMethodForGenericFromHandle); } else { il.Emit(OpCodes.Call, MethodBaseMethods.GetMethodFromHandle); // target method } EmitLoadConstant(il, methodParameters.Length); il.Emit(OpCodes.Newarr, typeof(object)); // object[] parameters if (methodParameters.Length > 0) { il.Emit(OpCodes.Stloc, parameterArray); for (int i = 0; i < methodParameters.Length; ++i) { il.Emit(OpCodes.Ldloc, parameterArray); EmitLoadConstant(il, i); EmitLoadArgument(il, i); Type elementType = paramMapper.GetParameterType(methodParameters[i].ParameterType); if (elementType.IsByRef) { elementType = paramMapper.GetElementType(methodParameters[i].ParameterType); il.Emit(OpCodes.Ldobj, elementType); } EmitBox(il, elementType); il.Emit(OpCodes.Stelem_Ref); } il.Emit(OpCodes.Ldloc, parameterArray); } il.Emit(OpCodes.Newobj, VirtualMethodInvocationMethods.VirtualMethodInvocation); il.Emit(OpCodes.Stloc, inputs); il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Ldfld, proxyInterceptionPipelineField); il.Emit(OpCodes.Ldloc, inputs); // Put delegate reference onto the stack il.Emit(OpCodes.Ldarg_0); MethodInfo callTarget = delegateMethod; if (callTarget.IsGenericMethod) { callTarget = delegateMethod.MakeGenericMethod(paramMapper.GenericMethodParameters); } il.Emit(OpCodes.Ldftn, callTarget); il.Emit(OpCodes.Newobj, InvokeInterceptionBehaviorDelegateMethods.InvokeInterceptionBehaviorDelegate); // And call the pipeline il.Emit(OpCodes.Call, InterceptionBehaviorPipelineMethods.Invoke); il.Emit(OpCodes.Stloc, methodReturn); // Was there an exception? Label noException = il.DefineLabel(); il.Emit(OpCodes.Ldloc, methodReturn); il.EmitCall(OpCodes.Callvirt, IMethodReturnMethods.GetException, null); il.Emit(OpCodes.Stloc, ex); il.Emit(OpCodes.Ldloc, ex); il.Emit(OpCodes.Ldnull); il.Emit(OpCodes.Ceq); il.Emit(OpCodes.Brtrue_S, noException); il.Emit(OpCodes.Ldloc, ex); il.Emit(OpCodes.Throw); il.MarkLabel(noException); // Unpack any ref/out parameters if (methodParameters.Length > 0) { int outputArgNum = 0; for (paramNum = 0; paramNum < methodParameters.Length; ++paramNum) { ParameterInfo pi = methodParameters[paramNum]; if (pi.ParameterType.IsByRef) { // Get the original parameter value - address of the ref or out EmitLoadArgument(il, paramNum); // Get the value of this output parameter out of the Outputs collection il.Emit(OpCodes.Ldloc, methodReturn); il.Emit(OpCodes.Callvirt, IMethodReturnMethods.GetOutputs); EmitLoadConstant(il, outputArgNum++); il.Emit(OpCodes.Callvirt, IListMethods.GetItem); EmitUnboxOrCast(il, paramMapper.GetElementType(pi.ParameterType)); // And store in the caller il.Emit(OpCodes.Stobj, paramMapper.GetElementType(pi.ParameterType)); } } } if (MethodHasReturnValue) { il.Emit(OpCodes.Ldloc, methodReturn); il.EmitCall(OpCodes.Callvirt, IMethodReturnMethods.GetReturnValue, null); EmitUnboxOrCast(il, paramMapper.GetReturnType()); } il.Emit(OpCodes.Ret); return methodBuilder; } private bool MethodHasReturnValue { get { return methodToOverride.ReturnType != typeof(void); } } /// <summary> /// Used to throw an <see cref="NotImplementedException"/> for non-implemented methods on the /// additional interfaces. /// </summary> public static Exception BuildAdditionalInterfaceNonImplementedException() { return new NotImplementedException(Resources.ExceptionAdditionalInterfaceNotImplemented); } } }