/// <summary> /// If a proxy type has not been generated yet, generates a proxy type that implements /// TInterface and forwards calls to an object of the type given in the constructor. /// </summary> private void GenerateProxyType() { if (m_ProxyType == null) { AppDomain domain = Thread.GetDomain(); AssemblyBuilder assembly = domain.DefineDynamicAssembly(new AssemblyName("DuckProxy_" + typeof(TInterface).FullName.Replace(".", "_") + "_" + m_DuckType.FullName.Replace(".", "_")), AssemblyBuilderAccess.Run); ModuleBuilder module = assembly.DefineDynamicModule("DuckProxy"); TypeBuilder proxyType = module.DefineType("DuckProxy"); proxyType.AddInterfaceImplementation(typeof(IDuckProxy)); proxyType.AddInterfaceImplementation(typeof(TInterface)); // Define private field to hold a reference to the duck object to forward calls to. FieldBuilder duckField = proxyType.DefineField("m_Duck", m_DuckType, FieldAttributes.Private); // Define private .ctor(duckType duck) ConstructorBuilder constructor = proxyType.DefineConstructor(MethodAttributes.Private, CallingConventions.HasThis, new Type[] { m_DuckType }); ILGenerator constructorIL = constructor.GetILGenerator(); constructorIL.Emit(OpCodes.Ldarg_0); constructorIL.Emit(OpCodes.Ldarg_1); constructorIL.Emit(OpCodes.Stfld, duckField); constructorIL.Emit(OpCodes.Ret); // Define public static TInterface Wrap(object duck) MethodBuilder wrapMethod = proxyType.DefineMethod("Wrap", MethodAttributes.Public | MethodAttributes.Static, CallingConventions.Standard, typeof(TInterface), new Type[] { typeof(object) }); ILGenerator wrapMethodIL = wrapMethod.GetILGenerator(); wrapMethodIL.Emit(OpCodes.Ldarg_0); if (m_DuckType.IsValueType) { wrapMethodIL.Emit(OpCodes.Box, m_DuckType); } wrapMethodIL.Emit(OpCodes.Newobj, constructor); wrapMethodIL.Emit(OpCodes.Ret); // Define public object UnwrapDuck() - Implementation of IDuckProxy MethodBuilder unwrapMethod = proxyType.DefineMethod("UnwrapDuck", MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.Final, CallingConventions.HasThis, typeof(object), new Type[0]); ILGenerator unwrapMethodIL = unwrapMethod.GetILGenerator(); unwrapMethodIL.Emit(OpCodes.Ldarg_0); unwrapMethodIL.Emit(OpCodes.Ldfld, duckField); if (m_DuckType.IsValueType) { unwrapMethodIL.Emit(OpCodes.Box, m_DuckType); } unwrapMethodIL.Emit(OpCodes.Ret); // Define all members of TInterface MemberInfo[] members = typeof(TInterface).GetMembers(); ProxyMemberDictionary proxyMembers = new ProxyMemberDictionary(); foreach (MemberInfo member in members) { ImplementMember(proxyType, proxyMembers, duckField, member); } m_ProxyType = proxyType.CreateType(); m_WrapDuck = (WrapDuckDelegate)(Delegate.CreateDelegate(typeof(WrapDuckDelegate), m_ProxyType, wrapMethod.Name)); } }
/// <summary> /// If a proxy type has not been generated yet, generates a proxy type that defines a method /// matching the method signature of the to delegate type given in the constructor which forwards /// calls to a delegate of the from type given in the constructor. /// </summary> private void GenerateProxyType() { if (m_ProxyType == null) { if (!CanProxy()) { throw new ArgumentException(m_FromDelegateType.FullName + " is not compatible with " + m_ToDelegateType.FullName + "."); } AssemblyBuilderAccess assemblyBuilderAccess; //#if !DEBUG assemblyBuilderAccess = AssemblyBuilderAccess.Run; //#else //assemblyBuilderAccess = AssemblyBuilderAccess.RunAndSave; //#endif AppDomain domain = Thread.GetDomain(); string assemblyName = "DuckDelegateProxy_" + m_ToDelegateType.Name.Replace(".", "_").Replace("+", "-") + "_" + m_FromDelegateType.Name.Replace(".", "_").Replace("+", "-") + ".dll"; AssemblyBuilder assembly = domain.DefineDynamicAssembly(new AssemblyName(assemblyName), assemblyBuilderAccess); ModuleBuilder module = assembly.DefineDynamicModule(assemblyName); TypeBuilder proxyType = module.DefineType("DuckDelegateProxy"); proxyType.AddInterfaceImplementation(typeof(IDuckProxy)); // Define private field to hold a reference to the duck delegate to forward calls to. FieldBuilder duckDelegateField = proxyType.DefineField("m_DuckDelegate", m_FromDelegateType, FieldAttributes.Private); // Define private .ctor(duckDelegateType duckDelegate) ConstructorBuilder constructor = proxyType.DefineConstructor(MethodAttributes.Private, CallingConventions.HasThis, new Type[] { m_FromDelegateType }); ILGenerator constructorIL = constructor.GetILGenerator(); constructorIL.Emit(OpCodes.Ldarg_0); constructorIL.Emit(OpCodes.Ldarg_1); constructorIL.Emit(OpCodes.Stfld, duckDelegateField); constructorIL.Emit(OpCodes.Ret); // Define Invoke method MethodBuilder invokeMethod = ImplementInvokeMethod(proxyType, duckDelegateField); // Define public static Delegate Wrap(Delegate duck) MethodBuilder wrapMethod = proxyType.DefineMethod("Wrap", MethodAttributes.Public | MethodAttributes.Static, CallingConventions.Standard, typeof(Delegate), new Type[] { typeof(Delegate) }); ILGenerator wrapMethodIL = wrapMethod.GetILGenerator(); wrapMethodIL.Emit(OpCodes.Ldarg_0); wrapMethodIL.Emit(OpCodes.Newobj, constructor); wrapMethodIL.Emit(OpCodes.Ldftn, invokeMethod); wrapMethodIL.Emit(OpCodes.Newobj, m_ToDelegateType.GetConstructor(new Type[] { typeof(object), typeof(IntPtr) })); wrapMethodIL.Emit(OpCodes.Ret); // Define public object UnwrapDuck() - Implementation of IDuckProxy MethodBuilder unwrapMethod = proxyType.DefineMethod("UnwrapDuck", MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.Final, CallingConventions.HasThis, typeof(object), new Type[0]); ILGenerator unwrapMethodIL = unwrapMethod.GetILGenerator(); unwrapMethodIL.Emit(OpCodes.Ldarg_0); unwrapMethodIL.Emit(OpCodes.Ldfld, duckDelegateField); unwrapMethodIL.Emit(OpCodes.Ret); // Bake it m_ProxyType = proxyType.CreateType(); m_WrapDuck = (WrapDuckDelegate)(Delegate.CreateDelegate(typeof(WrapDuckDelegate), m_ProxyType, wrapMethod.Name)); m_InvokeMethod = m_ProxyType.GetMethod("Invoke"); //#if DEBUG // If we're in debug mode, save the assembly so we can disassemble it if we want. //assembly.Save(assemblyName); //#endif } }
/// <summary> /// If a proxy type has not been generated yet, generates a proxy type that implements /// the interface type given in the constructor and forwards calls to an object of the /// duck type given in the constructor. /// </summary> private void GenerateProxyType() { if (m_ProxyType == null) { AssemblyBuilderAccess assemblyBuilderAccess; #if !DEBUG assemblyBuilderAccess = AssemblyBuilderAccess.Run; #else assemblyBuilderAccess = AssemblyBuilderAccess.RunAndSave; #endif AppDomain domain = Thread.GetDomain(); string assemblyName = "DuckInterfaceProxy_" + m_InterfaceType.Name.Replace(".", "_").Replace("+", "-") + "_" + m_DuckType.Name.Replace(".", "_").Replace("+", "-") + ".dll"; AssemblyBuilder assembly = domain.DefineDynamicAssembly(new AssemblyName(assemblyName), assemblyBuilderAccess); ModuleBuilder module = assembly.DefineDynamicModule(assemblyName); TypeBuilder proxyType = module.DefineType("DuckProxy"); proxyType.AddInterfaceImplementation(typeof(IDuckProxy)); proxyType.AddInterfaceImplementation(m_InterfaceType); FieldBuilder duckField; ConstructorBuilder constructor; ILGenerator constructorIL; MethodBuilder wrapMethod; if (!m_IsDuckStatic) { // Define private field to hold a reference to the duck object to forward calls to. duckField = proxyType.DefineField("m_Duck", m_DuckType, FieldAttributes.Private); // Define private .ctor(duckType duck) constructor = proxyType.DefineConstructor(MethodAttributes.Private, CallingConventions.HasThis, new Type[] { m_DuckType }); constructorIL = constructor.GetILGenerator(); constructorIL.Emit(OpCodes.Ldarg_0); constructorIL.Emit(OpCodes.Ldarg_1); constructorIL.Emit(OpCodes.Stfld, duckField); // constructorIL is passed to other methods so that they can add code to the constructor. // constructorIL.Emit(OpCodes.Ret); - This code should appear below after other methods are called. // Define public static object Wrap(object duck) wrapMethod = proxyType.DefineMethod("Wrap", MethodAttributes.Public | MethodAttributes.Static, CallingConventions.Standard, typeof(object), new Type[] { typeof(object) }); ILGenerator wrapMethodIL = wrapMethod.GetILGenerator(); wrapMethodIL.Emit(OpCodes.Ldarg_0); if (m_DuckType.IsValueType) { wrapMethodIL.Emit(OpCodes.Box, m_DuckType); } wrapMethodIL.Emit(OpCodes.Newobj, constructor); wrapMethodIL.Emit(OpCodes.Ret); // Define public object UnwrapDuck() - Implementation of IDuckProxy MethodBuilder unwrapMethod = proxyType.DefineMethod("UnwrapDuck", MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.Final, CallingConventions.HasThis, typeof(object), new Type[0]); ILGenerator unwrapMethodIL = unwrapMethod.GetILGenerator(); unwrapMethodIL.Emit(OpCodes.Ldarg_0); unwrapMethodIL.Emit(OpCodes.Ldfld, duckField); if (m_DuckType.IsValueType) { unwrapMethodIL.Emit(OpCodes.Box, m_DuckType); } unwrapMethodIL.Emit(OpCodes.Ret); // Override public bool Equals() method MethodBuilder equalsMethod = proxyType.DefineMethod("Equals", MethodAttributes.Public | MethodAttributes.Virtual, CallingConventions.HasThis, typeof(bool), new Type[] { typeof(object) }); MethodInfo objectEqualsMethod = typeof(object).GetMethod("Equals", new Type[] { typeof(object) }); proxyType.DefineMethodOverride(equalsMethod, objectEqualsMethod); ILGenerator equalsMethodIL = equalsMethod.GetILGenerator(); equalsMethodIL.Emit(OpCodes.Ldarg_0); equalsMethodIL.Emit(OpCodes.Ldfld, duckField); equalsMethodIL.Emit(OpCodes.Ldarg_1); equalsMethodIL.Emit(OpCodes.Call, typeof(DuckTyping).GetMethod("Uncast", new Type[] { typeof(object) })); equalsMethodIL.Emit(OpCodes.Callvirt, objectEqualsMethod); equalsMethodIL.Emit(OpCodes.Ret); // Override public int GetHashCode() method MethodBuilder getHashCodeMethod = proxyType.DefineMethod("GetHashCode", MethodAttributes.Public | MethodAttributes.Virtual, CallingConventions.HasThis, typeof(int), new Type[0]); MethodInfo objectGetHashCodeMethod = typeof(object).GetMethod("GetHashCode", new Type[0]); proxyType.DefineMethodOverride(getHashCodeMethod, objectGetHashCodeMethod); ILGenerator getHashCodeMethodIL = getHashCodeMethod.GetILGenerator(); getHashCodeMethodIL.Emit(OpCodes.Ldarg_0); getHashCodeMethodIL.Emit(OpCodes.Ldfld, duckField); getHashCodeMethodIL.Emit(OpCodes.Callvirt, objectGetHashCodeMethod); getHashCodeMethodIL.Emit(OpCodes.Ret); // Override string ToString() method MethodBuilder toStringMethod = proxyType.DefineMethod("ToString", MethodAttributes.Public | MethodAttributes.Virtual, CallingConventions.HasThis, typeof(string), new Type[0]); MethodInfo objectToStringMethod = typeof(object).GetMethod("ToString", new Type[0]); proxyType.DefineMethodOverride(toStringMethod, objectToStringMethod); ILGenerator toStringMethodIL = toStringMethod.GetILGenerator(); toStringMethodIL.Emit(OpCodes.Ldarg_0); toStringMethodIL.Emit(OpCodes.Ldfld, duckField); toStringMethodIL.Emit(OpCodes.Callvirt, objectToStringMethod); toStringMethodIL.Emit(OpCodes.Ret); } else { duckField = null; // Define public .ctor() constructor = proxyType.DefineConstructor(MethodAttributes.Public, CallingConventions.HasThis, new Type[0]); constructorIL = constructor.GetILGenerator(); wrapMethod = null; // Define public object UnwrapDuck() - Implementation of IDuckProxy MethodBuilder unwrapMethod = proxyType.DefineMethod("UnwrapDuck", MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.Final, CallingConventions.HasThis, typeof(object), new Type[0]); ILGenerator unwrapMethodIL = unwrapMethod.GetILGenerator(); unwrapMethodIL.Emit(OpCodes.Ldnull); unwrapMethodIL.Emit(OpCodes.Ret); } // Define all members of m_InterfaceType ProxyMemberDictionary proxyMembers = new ProxyMemberDictionary(); ImplementInterface(proxyType, proxyMembers, duckField, constructorIL, m_InterfaceType); // Now that we are done implementing members, finish constructor method body: constructorIL.Emit(OpCodes.Ret); // Bake it m_ProxyType = proxyType.CreateType(); if (!m_IsDuckStatic) { m_WrapDuck = (WrapDuckDelegate)(Delegate.CreateDelegate(typeof(WrapDuckDelegate), m_ProxyType, wrapMethod.Name)); } else { m_StaticProxy = Activator.CreateInstance(m_ProxyType); } //#if DEBUG // If we're in debug mode, save the assembly so we can disassemble it if we want. //assembly.Save(assemblyName); //#endif } }