private static void ImplementGetIdentifier(
            TypeBuilder typeBuilder, MethodInfo method, FieldInfo lazyInitializerField, System.Type parentType)
        {
            /*
             * get
             * {
             *      if (this.__lazyInitializer == null)
             *              return base.get_<Identifier>();
             *      return (<ReturnType>)this.__lazyInitializer.Identifier;
             * }
             */
            var methodOverride = ProxyBuilderHelper.GenerateMethodSignature(method.Name, method, typeBuilder);

            var IL = methodOverride.GetILGenerator();

            EmitCallBaseIfLazyInitializerIsNull(IL, method, lazyInitializerField, parentType);

            IL.Emit(OpCodes.Ldarg_0);
            IL.Emit(OpCodes.Ldfld, lazyInitializerField);
            IL.Emit(OpCodes.Callvirt, LazyInitializerIdentifierProperty.GetMethod);
            IL.Emit(OpCodes.Unbox_Any, method.ReturnType);
            IL.Emit(OpCodes.Ret);

            typeBuilder.DefineMethodOverride(methodOverride, method);
        }
Esempio n. 2
0
        public TypeInfo CreateProxyType(System.Type baseType, IReadOnlyCollection <System.Type> baseInterfaces)
        {
            var typeName     = $"{baseType.Name}Proxy";
            var assemblyName = $"{typeName}Assembly";
            var moduleName   = $"{typeName}Module";

            var name = new AssemblyName(assemblyName);

            var assemblyBuilder = ProxyBuilderHelper.DefineDynamicAssembly(AppDomain.CurrentDomain, name);
            var moduleBuilder   = ProxyBuilderHelper.DefineDynamicModule(assemblyBuilder, moduleName);

            const TypeAttributes typeAttributes = TypeAttributes.AutoClass | TypeAttributes.Class | TypeAttributes.Public | TypeAttributes.BeforeFieldInit;

            var interfaces = new HashSet <System.Type>
            {
                // Add the ISerializable interface so that it can be implemented
                typeof(ISerializable)
            };

            interfaces.UnionWith(baseInterfaces);
            interfaces.UnionWith(baseInterfaces.SelectMany(i => i.GetInterfaces()));
            interfaces.UnionWith(baseType.GetInterfaces());

            // Use the object as the base type
            // since we're not inheriting from any class type
            var parentType = baseType;

            if (baseType.IsInterface)
            {
                parentType = typeof(object);
                interfaces.Add(baseType);
            }

            interfaces.RemoveWhere(i => !i.IsVisible);

            var typeBuilder = moduleBuilder.DefineType(typeName, typeAttributes, parentType, interfaces.ToArray());

            var lazyInitializerField = typeBuilder.DefineField("__lazyInitializer", LazyInitializerType, FieldAttributes.Private);
            var proxyInfoField       = typeBuilder.DefineField("__proxyInfo", typeof(NHibernateProxyFactoryInfo), FieldAttributes.Private);

            ImplementConstructor(typeBuilder, parentType, lazyInitializerField, proxyInfoField);

            // Provide a custom implementation of ISerializable instead of redirecting it back to the interceptor
            foreach (var method in ProxyBuilderHelper.GetProxiableMethods(baseType, interfaces.Except(new[] { typeof(ISerializable) })))
            {
                CreateProxiedMethod(typeBuilder, method, lazyInitializerField);
            }

            ProxyBuilderHelper.MakeProxySerializable(typeBuilder);
            ImplementDeserializationConstructor(typeBuilder, parentType);
            ImplementGetObjectData(typeBuilder, proxyInfoField, lazyInitializerField);

            var proxyType = typeBuilder.CreateTypeInfo();

            ProxyBuilderHelper.Save(assemblyBuilder);

            return(proxyType);
        }
        public static TypeInfo CreateProxyType(System.Type baseType)
        {
            // Avoid having a suffix ending with "Proxy", for disambiguation with INHibernateProxy proxies
            var typeName     = $"{baseType.Name}ProxyForFieldInterceptor";
            var assemblyName = $"{typeName}Assembly";
            var moduleName   = $"{typeName}Module";

            var name = new AssemblyName(assemblyName);

            var assemblyBuilder = ProxyBuilderHelper.DefineDynamicAssembly(AppDomain.CurrentDomain, name);
            var moduleBuilder   = ProxyBuilderHelper.DefineDynamicModule(assemblyBuilder, moduleName);

            const TypeAttributes typeAttributes = TypeAttributes.AutoClass | TypeAttributes.Class | TypeAttributes.Public | TypeAttributes.BeforeFieldInit;

            var interfaces = new HashSet <System.Type>
            {
                typeof(IFieldInterceptorAccessor),
                typeof(ISerializable)
            };

            // Use the object as the base type
            // since we're not inheriting from any class type
            var parentType = baseType;

            if (baseType.IsInterface)
            {
                throw new ArgumentException(
                          $"Field interceptor proxy does not support being build on an interface baseType ({baseType.FullName}).",
                          nameof(baseType));
            }

            interfaces.RemoveWhere(i => !i.IsVisible);

            var typeBuilder = moduleBuilder.DefineType(typeName, typeAttributes, parentType, interfaces.ToArray());

            var fieldInterceptorField = typeBuilder.DefineField("__fieldInterceptor", FieldInterceptorType, FieldAttributes.Private);
            var proxyInfoField        = typeBuilder.DefineField("__proxyInfo", typeof(NHibernateProxyFactoryInfo), FieldAttributes.Private);

            ImplementConstructor(typeBuilder, parentType, proxyInfoField);

            // Provide a custom implementation of ISerializable instead of redirecting it back to the interceptor
            foreach (var method in ProxyBuilderHelper.GetProxiableMethods(baseType, interfaces.Except(new[] { typeof(ISerializable) })))
            {
                CreateProxiedMethod(typeBuilder, method, fieldInterceptorField);
            }

            ProxyBuilderHelper.MakeProxySerializable(typeBuilder);
            ImplementDeserializationConstructor(typeBuilder, parentType);
            ImplementGetObjectData(typeBuilder, proxyInfoField, fieldInterceptorField, parentType);

            var proxyType = typeBuilder.CreateTypeInfo();

            ProxyBuilderHelper.Save(assemblyBuilder);

            return(proxyType);
        }
 private static void ImplementISerializable(
     TypeBuilder typeBuilder,
     FieldInfo proxyInfoField,
     FieldInfo fieldInterceptorField,
     System.Type baseType)
 {
     ProxyBuilderHelper.MakeProxySerializable(typeBuilder);
     ImplementDeserializationConstructor(typeBuilder, baseType);
     ImplementGetObjectData(typeBuilder, proxyInfoField, fieldInterceptorField, baseType);
 }
        private static void ImplementSet(TypeBuilder typeBuilder, MethodInfo setter, FieldInfo fieldInterceptorField)
        {
            /*
             *      if (this.__fieldInterceptor != null)
             *      {
             *              this.__fieldInterceptor.MarkDirty();
             *              this.__fieldInterceptor.Intercept(this, <ReflectHelper.GetPropertyName(setter)>, value, true);
             *      }
             *      base.<setter>(value);
             */
            var methodOverride = ProxyBuilderHelper.GenerateMethodSignature(setter.Name, setter, typeBuilder);

            var IL = methodOverride.GetILGenerator();

            // if (this.__fieldInterceptor != null)
            IL.Emit(OpCodes.Ldarg_0);
            IL.Emit(OpCodes.Ldfld, fieldInterceptorField);
            IL.Emit(OpCodes.Ldnull);
            var skipInterceptor = IL.DefineLabel();

            IL.Emit(OpCodes.Beq, skipInterceptor);

            // this.__fieldInterceptor.MarkDirty();
            IL.Emit(OpCodes.Ldarg_0);
            IL.Emit(OpCodes.Ldfld, fieldInterceptorField);
            IL.Emit(OpCodes.Callvirt, FieldInterceptorMarkDirtyMethod);

            // this.__fieldInterceptor.Intercept(this, <ReflectHelper.GetPropertyName(setter)>, propValue, true);
            IL.Emit(OpCodes.Ldarg_0);
            IL.Emit(OpCodes.Ldfld, fieldInterceptorField);
            IL.Emit(OpCodes.Ldarg_0);
            IL.Emit(OpCodes.Ldstr, ReflectHelper.GetPropertyName(setter));
            IL.Emit(OpCodes.Ldarg_1);
            var propertyType = setter.GetParameters()[0].ParameterType;

            if (propertyType.IsValueType)
            {
                IL.Emit(OpCodes.Box, propertyType);
            }
            IL.Emit(OpCodes.Ldc_I4_1);
            IL.EmitCall(OpCodes.Call, FieldInterceptorInterceptExtensionMethod, null);
            IL.Emit(OpCodes.Pop);

            // end if (this.__fieldInterceptor != null)
            IL.MarkLabel(skipInterceptor);

            // base.<setter>(value);
            IL.Emit(OpCodes.Ldarg_0);
            IL.Emit(OpCodes.Ldarg_1);
            IL.Emit(OpCodes.Call, setter);

            IL.Emit(OpCodes.Ret);

            typeBuilder.DefineMethodOverride(methodOverride, setter);
        }
        public static TypeInfo CreateProxyType(System.Type baseType)
        {
            if (baseType.IsInterface)
            {
                throw new ArgumentException(
                          $"Field interceptor proxy does not support being build on an interface baseType ({baseType.FullName}).",
                          nameof(baseType));
            }

            // Avoid having a suffix ending with "Proxy", for disambiguation with INHibernateProxy proxies
            var typeName     = $"{baseType.Name}ProxyForFieldInterceptor";
            var assemblyName = $"{typeName}Assembly";
            var moduleName   = $"{typeName}Module";

            var name = new AssemblyName(assemblyName);

            var assemblyBuilder = ProxyBuilderHelper.DefineDynamicAssembly(AppDomain.CurrentDomain, name);

#if NETFX || NETCOREAPP2_0
            if (!baseType.IsVisible)
            {
                ProxyBuilderHelper.GenerateInstanceOfIgnoresAccessChecksToAttribute(assemblyBuilder, baseType.Assembly.GetName().Name);
            }
#endif
            var moduleBuilder = ProxyBuilderHelper.DefineDynamicModule(assemblyBuilder, moduleName);

            const TypeAttributes typeAttributes = TypeAttributes.AutoClass | TypeAttributes.Class | TypeAttributes.Public | TypeAttributes.BeforeFieldInit;

            var interfaces = new[]
            {
                typeof(IFieldInterceptorAccessor),
                typeof(ISerializable)
            };
            var typeBuilder = moduleBuilder.DefineType(typeName, typeAttributes, baseType, interfaces);

            var fieldInterceptorField = typeBuilder.DefineField("__fieldInterceptor", FieldInterceptorType, FieldAttributes.Private);
            var proxyInfoField        = typeBuilder.DefineField("__proxyInfo", typeof(NHibernateProxyFactoryInfo), FieldAttributes.Private);

            ImplementConstructor(typeBuilder, baseType, proxyInfoField);

            foreach (var method in ProxyBuilderHelper.GetProxiableMethods(baseType))
            {
                CreateProxiedMethod(typeBuilder, method, fieldInterceptorField);
            }

            ImplementIFieldInterceptorAccessor(typeBuilder, fieldInterceptorField);
            ImplementISerializable(typeBuilder, proxyInfoField, fieldInterceptorField, baseType);

            var proxyType = typeBuilder.CreateTypeInfo();

            ProxyBuilderHelper.Save(assemblyBuilder);

            return(proxyType);
        }
        private static void ImplementDeserializationConstructor(TypeBuilder typeBuilder, System.Type parentType)
        {
            var parameterTypes = new[] { typeof(SerializationInfo), typeof(StreamingContext) };
            var constructor    = typeBuilder.DefineConstructor(constructorAttributes, CallingConventions.Standard, parameterTypes);

            constructor.SetImplementationFlags(MethodImplAttributes.IL | MethodImplAttributes.Managed);

            var IL = constructor.GetILGenerator();

            ProxyBuilderHelper.CallDefaultBaseConstructor(IL, parentType);
            //Everything is done in NHibernateProxyObjectReference, so just return data.
            IL.Emit(OpCodes.Ret);
        }
        private static void ImplementConstructor(TypeBuilder typeBuilder, System.Type parentType, FieldInfo proxyInfoField)
        {
            var constructor = typeBuilder.DefineConstructor(constructorAttributes, CallingConventions.Standard, new[] { typeof(NHibernateProxyFactoryInfo) });

            constructor.SetImplementationFlags(MethodImplAttributes.IL | MethodImplAttributes.Managed);

            var IL = constructor.GetILGenerator();

            ProxyBuilderHelper.CallDefaultBaseConstructor(IL, parentType);

            // __proxyInfo == proxyInfo;
            IL.Emit(OpCodes.Ldarg_0);
            IL.Emit(OpCodes.Ldarg_1);
            IL.Emit(OpCodes.Stfld, proxyInfoField);

            IL.Emit(OpCodes.Ret);
        }
Esempio n. 9
0
        private static void ImplementCallMethodOnImplementation(TypeBuilder typeBuilder, MethodInfo method, FieldInfo lazyInitializerField)
        {
            /*
             *      if (this.__lazyInitializer == null)
             *              return base.<Method>(args..);
             *      return this.__lazyInitializer.GetImplementation().<Method>(args..)
             */
            var methodOverride = ProxyBuilderHelper.GenerateMethodSignature(method.Name, method, typeBuilder);

            var IL = methodOverride.GetILGenerator();

            EmitCallBaseIfLazyInitializerIsNull(IL, method, lazyInitializerField);

            EmitCallImplementation(IL, method, lazyInitializerField);
            IL.Emit(OpCodes.Ret);

            typeBuilder.DefineMethodOverride(methodOverride, method);
        }
        private static void ImplementDeserializationConstructor(TypeBuilder typeBuilder, System.Type parentType)
        {
            var parameterTypes = new[] { typeof(SerializationInfo), typeof(StreamingContext) };
            var constructor    = typeBuilder.DefineConstructor(constructorAttributes, CallingConventions.Standard, parameterTypes);

            constructor.SetImplementationFlags(MethodImplAttributes.IL | MethodImplAttributes.Managed);

            var IL = constructor.GetILGenerator();

            if (typeof(ISerializable).IsAssignableFrom(parentType))
            {
                var baseConstructor = parentType.GetConstructor(
                    BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public,
                    null,
                    parameterTypes,
                    null);
                if (baseConstructor == null)
                {
                    // Throw new InvalidOperationException(<message>);
                    IL.Emit(
                        OpCodes.Ldstr,
                        $"Proxy for class {parentType.FullName} cannot be deserialized because the class implements " +
                        $"{nameof(ISerializable)} without having a deserialization constructor (see CA2229).");
                    IL.Emit(OpCodes.Newobj, InvalidOperationWithMessageConstructor);
                    IL.Emit(OpCodes.Throw);
                }
                else
                {
                    IL.Emit(OpCodes.Ldarg_0);
                    IL.Emit(OpCodes.Ldarg_1);
                    IL.Emit(OpCodes.Ldarg_2);
                    IL.Emit(OpCodes.Call, baseConstructor);
                }
            }
            else
            {
                ProxyBuilderHelper.CallDefaultBaseConstructor(IL, parentType);
            }

            // Everything else is done in FieldInterceptorObjectReference.
            IL.Emit(OpCodes.Ret);
        }
Esempio n. 11
0
        private static void ImplementCallMethodOnEmbeddedComponentId(TypeBuilder typeBuilder, MethodInfo method, FieldInfo lazyInitializerField)
        {
            /*
             *      if (this.__lazyInitializer == null)
             *              return base.<Method>(args..);
             *      this.__lazyInitializer.Identifier.<Method>(args..);
             */
            var methodOverride = ProxyBuilderHelper.GenerateMethodSignature(method.Name, method, typeBuilder);

            var IL = methodOverride.GetILGenerator();

            EmitCallBaseIfLazyInitializerIsNull(IL, method, lazyInitializerField);

            IL.Emit(OpCodes.Ldarg_0);
            IL.Emit(OpCodes.Ldfld, lazyInitializerField);
            IL.Emit(OpCodes.Callvirt, LazyInitializerIdentifierProperty.GetMethod);
            IL.Emit(OpCodes.Unbox_Any, method.DeclaringType);
            EmitCallMethod(IL, OpCodes.Callvirt, method);
            IL.Emit(OpCodes.Ret);

            typeBuilder.DefineMethodOverride(methodOverride, method);
        }
Esempio n. 12
0
        private static void ImplementGetObjectData(TypeBuilder typeBuilder, FieldInfo proxyInfoField, FieldInfo lazyInitializerField)
        {
            var methodBuilder = ProxyBuilderHelper.GetObjectDataMethodBuilder(typeBuilder);

            var IL = methodBuilder.GetILGenerator();

            // info.SetType(typeof(NHibernateProxyObjectReference));
            IL.Emit(OpCodes.Ldarg_1);
            IL.Emit(OpCodes.Ldtoken, typeof(NHibernateProxyObjectReference));
            IL.Emit(OpCodes.Call, ReflectionCache.TypeMethods.GetTypeFromHandle);
            IL.Emit(OpCodes.Callvirt, ProxyBuilderHelper.SerializationInfoSetTypeMethod);

            // (new NHibernateProxyObjectReference(this.__proxyInfo, this.__lazyInitializer.Identifier)).GetObjectData(info, context);
            //this.__proxyInfo
            IL.Emit(OpCodes.Ldarg_0);
            IL.Emit(OpCodes.Ldfld, proxyInfoField);

            //this.__lazyInitializer.Identifier
            IL.Emit(OpCodes.Ldarg_0);
            IL.Emit(OpCodes.Ldfld, lazyInitializerField);
            IL.Emit(OpCodes.Callvirt, LazyInitializerIdentifierProperty.GetMethod);

            var constructor = typeof(NHibernateProxyObjectReference).GetConstructor(
                new[]
            {
                typeof(NHibernateProxyFactoryInfo),
                typeof(object),
            });

            IL.Emit(OpCodes.Newobj, constructor);

            IL.Emit(OpCodes.Ldarg_1);
            IL.Emit(OpCodes.Ldarg_2);
            IL.Emit(OpCodes.Callvirt, ProxyBuilderHelper.SerializableGetObjectDataMethod);

            IL.Emit(OpCodes.Ret);

            typeBuilder.DefineMethodOverride(methodBuilder, ProxyBuilderHelper.SerializableGetObjectDataMethod);
        }
        private static void ImplementSetIdentifier(
            TypeBuilder typeBuilder, MethodInfo method, FieldInfo lazyInitializerField, System.Type parentType)
        {
            /*
             * set
             * {
             *      if (this.__lazyInitializer == null)
             *              return base.set_<Identifier>(value);
             *      this.__lazyInitializer.Initialize();
             *      this.__lazyInitializer.Identifier = value;
             *      this.__lazyInitializer.GetImplementation().<Identifier> = value;
             * }
             */
            var propertyType   = method.GetParameters()[0].ParameterType;
            var methodOverride = ProxyBuilderHelper.GenerateMethodSignature(method.Name, method, typeBuilder);
            var IL             = methodOverride.GetILGenerator();

            EmitCallBaseIfLazyInitializerIsNull(IL, method, lazyInitializerField, parentType);

            IL.Emit(OpCodes.Ldarg_0);
            IL.Emit(OpCodes.Ldfld, lazyInitializerField);
            IL.Emit(OpCodes.Callvirt, LazyInitializerInitializeMethod);

            IL.Emit(OpCodes.Ldarg_0);
            IL.Emit(OpCodes.Ldfld, lazyInitializerField);
            IL.Emit(OpCodes.Ldarg_1);
            if (propertyType.IsValueType)
            {
                IL.Emit(OpCodes.Box, propertyType);
            }
            IL.Emit(OpCodes.Callvirt, LazyInitializerIdentifierProperty.SetMethod);

            EmitCallImplementation(IL, method, lazyInitializerField);

            IL.Emit(OpCodes.Ret);

            typeBuilder.DefineMethodOverride(methodOverride, method);
        }
        private static void ImplementGet(TypeBuilder typeBuilder, MethodInfo getter, FieldInfo fieldInterceptorField)
        {
            /*
             *      var propValue = base.<getter>();
             *      if (this.__fieldInterceptor != null)
             *      {
             *              var result = this.__fieldInterceptor.Intercept(this, <ReflectHelper.GetPropertyName(getter)>, propValue);
             *
             *              if (result != AbstractFieldInterceptor.InvokeImplementation)
             *              {
             *                      return (<getter.ReturnType>)result;
             *              }
             *      }
             *      return propValue;
             */
            var methodOverride = ProxyBuilderHelper.GenerateMethodSignature(getter.Name, getter, typeBuilder);

            var IL = methodOverride.GetILGenerator();

            IL.DeclareLocal(getter.ReturnType);          // propValue
            IL.DeclareLocal(typeof(object));             // result

            // var propValue = base.<getter>();
            IL.Emit(OpCodes.Ldarg_0);
            IL.Emit(OpCodes.Call, getter);
            IL.Emit(OpCodes.Stloc_0);

            // if (this.__fieldInterceptor != null)
            IL.Emit(OpCodes.Ldarg_0);
            IL.Emit(OpCodes.Ldfld, fieldInterceptorField);
            IL.Emit(OpCodes.Ldnull);
            var skipInterceptor = IL.DefineLabel();

            IL.Emit(OpCodes.Beq, skipInterceptor);

            // var result = this.__fieldInterceptor.Intercept(this, <ReflectHelper.GetPropertyName(getter)>, propValue);
            IL.Emit(OpCodes.Ldarg_0);
            IL.Emit(OpCodes.Ldfld, fieldInterceptorField);
            IL.Emit(OpCodes.Ldarg_0);
            IL.Emit(OpCodes.Ldstr, ReflectHelper.GetPropertyName(getter));
            IL.Emit(OpCodes.Ldloc_0);
            if (getter.ReturnType.IsValueType)
            {
                IL.Emit(OpCodes.Box, getter.ReturnType);
            }
            IL.Emit(OpCodes.Callvirt, FieldInterceptorInterceptMethod);
            IL.Emit(OpCodes.Stloc_1);

            // if (result != AbstractFieldInterceptor.InvokeImplementation)
            IL.Emit(OpCodes.Ldloc_1);
            IL.Emit(OpCodes.Ldsfld, AbstractFieldInterceptorInvokeImplementationField);
            var skipInterceptorResult = IL.DefineLabel();

            IL.Emit(OpCodes.Beq, skipInterceptorResult);

            // return (<getter.ReturnType>)result;
            IL.Emit(OpCodes.Ldloc_1);
            IL.Emit(OpCodes.Unbox_Any, getter.ReturnType);
            IL.Emit(OpCodes.Ret);

            // end if (result != AbstractFieldInterceptor.InvokeImplementation)
            IL.MarkLabel(skipInterceptorResult);

            // end if (this.__fieldInterceptor != null)
            IL.MarkLabel(skipInterceptor);

            // return propValue;
            IL.Emit(OpCodes.Ldloc_0);
            IL.Emit(OpCodes.Ret);

            typeBuilder.DefineMethodOverride(methodOverride, getter);
        }
        private static void ImplementGetObjectData(TypeBuilder typeBuilder, FieldInfo proxyInfoField, FieldInfo fieldInterceptorField, System.Type parentType)
        {
            var methodBuilder = ProxyBuilderHelper.GetObjectDataMethodBuilder(typeBuilder);

            var IL = methodBuilder.GetILGenerator();

            IL.DeclareLocal(FieldInterceptorObjectReferenceType);

            // info.SetType(<FieldInterceptorObjectReferenceType>);
            IL.Emit(OpCodes.Ldarg_1);
            IL.Emit(OpCodes.Ldtoken, FieldInterceptorObjectReferenceType);
            IL.Emit(OpCodes.Call, ReflectionCache.TypeMethods.GetTypeFromHandle);
            IL.Emit(OpCodes.Callvirt, ProxyBuilderHelper.SerializationInfoSetTypeMethod);

            // var objectReference = new FieldInterceptorObjectReference(this.__proxyInfo, this.__fieldInterceptor));
            IL.Emit(OpCodes.Ldarg_0);
            IL.Emit(OpCodes.Ldfld, proxyInfoField);
            IL.Emit(OpCodes.Ldarg_0);
            IL.Emit(OpCodes.Ldfld, fieldInterceptorField);
            IL.Emit(OpCodes.Newobj, FieldInterceptorObjectReferenceConstructor);
            IL.Emit(OpCodes.Stloc_0);

            // objectReference.GetObjectData(info, context);
            IL.Emit(OpCodes.Ldloc_0);
            IL.Emit(OpCodes.Ldarg_1);
            IL.Emit(OpCodes.Ldarg_2);
            IL.Emit(OpCodes.Callvirt, ProxyBuilderHelper.SerializableGetObjectDataMethod);

            if (typeof(ISerializable).IsAssignableFrom(parentType))
            {
                var parentGetObjectData = parentType.GetMethod(
                    nameof(ISerializable.GetObjectData),
                    BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance,
                    null,
                    new[] { typeof(SerializationInfo), typeof(StreamingContext) },
                    null);
                if (parentGetObjectData == null)
                {
                    // Throw new InvalidOperationException(<message>);
                    IL.Emit(
                        OpCodes.Ldstr,
                        $"Proxy for class {parentType.FullName} cannot be serialized because the class implements " +
                        $"{nameof(ISerializable)} without having a public or protected GetObjectData.");
                    IL.Emit(OpCodes.Newobj, InvalidOperationWithMessageConstructor);
                    IL.Emit(OpCodes.Throw);
                    typeBuilder.DefineMethodOverride(methodBuilder, ProxyBuilderHelper.SerializableGetObjectDataMethod);
                    return;
                }

                // base.GetObjectData(info, context);
                IL.Emit(OpCodes.Ldarg_0);
                IL.Emit(OpCodes.Ldarg_1);
                IL.Emit(OpCodes.Ldarg_2);
                IL.Emit(OpCodes.Call, parentGetObjectData);

                // objectReference.SetNoAdditionalData(info);
                IL.Emit(OpCodes.Ldloc_0);
                IL.Emit(OpCodes.Ldarg_1);
                IL.Emit(OpCodes.Callvirt, FieldInterceptorObjectReferenceSetNoAdditionalDataMethod);
            }
            else
            {
                // objectReference.SerializeBaseData(info, context, this, <parentType>);
                IL.Emit(OpCodes.Ldloc_0);
                IL.Emit(OpCodes.Ldarg_1);
                IL.Emit(OpCodes.Ldarg_2);
                IL.Emit(OpCodes.Ldarg_0);
                IL.Emit(OpCodes.Ldtoken, parentType);
                IL.Emit(OpCodes.Call, ReflectionCache.TypeMethods.GetTypeFromHandle);
                IL.Emit(OpCodes.Callvirt, FieldInterceptorObjectReferenceGetBaseDataMethod);
            }

            IL.Emit(OpCodes.Ret);

            typeBuilder.DefineMethodOverride(methodBuilder, ProxyBuilderHelper.SerializableGetObjectDataMethod);
        }
        public TypeInfo CreateProxyType(System.Type baseType, IReadOnlyCollection <System.Type> baseInterfaces)
        {
            System.Type interfaceType = null;
            if (baseType == typeof(object))
            {
                // Mapping option "proxy" allows to ask for using an interface, which switches the base type to object
                // and adds the interface to base interfaces set.
                // Avoids using object for naming the proxy, as otherwise all entities using the "proxy" option for
                // specifying an interface would have their proxies sharing the same full name.
                interfaceType = baseInterfaces.FirstOrDefault(i => i != typeof(INHibernateProxy));
            }
            var typeName     = $"{(interfaceType ?? baseType).Name}Proxy";
            var assemblyName = $"{typeName}Assembly";
            var moduleName   = $"{typeName}Module";

            var name = new AssemblyName(assemblyName);

            var assemblyBuilder = ProxyBuilderHelper.DefineDynamicAssembly(AppDomain.CurrentDomain, name);
            var moduleBuilder   = ProxyBuilderHelper.DefineDynamicModule(assemblyBuilder, moduleName);

            const TypeAttributes typeAttributes = TypeAttributes.AutoClass | TypeAttributes.Class | TypeAttributes.Public | TypeAttributes.BeforeFieldInit;

            var interfaces = new HashSet <System.Type>
            {
                // Add the ISerializable interface so that it can be implemented
                typeof(ISerializable)
            };

            interfaces.UnionWith(baseInterfaces);
            interfaces.UnionWith(baseInterfaces.SelectMany(i => i.GetInterfaces()));
            interfaces.UnionWith(baseType.GetInterfaces());

            // Use the object as the base type
            // since we're not inheriting from any class type
            var parentType = baseType;

            if (baseType.IsInterface)
            {
                parentType = typeof(object);
                interfaces.Add(baseType);
            }

#if NETFX || NETCOREAPP2_0
            var assemblyNamesToIgnoreAccessCheck =
                new[] { baseType }
            .Concat(interfaces).Where(i => !i.IsVisible)
            .Select(i => i.Assembly.GetName().Name)
            .Distinct();
            foreach (var a in assemblyNamesToIgnoreAccessCheck)
            {
                ProxyBuilderHelper.GenerateInstanceOfIgnoresAccessChecksToAttribute(assemblyBuilder, a);
            }
#else
            interfaces.RemoveWhere(i => !i.IsVisible);
#endif

            var typeBuilder = moduleBuilder.DefineType(typeName, typeAttributes, parentType, interfaces.ToArray());

            var lazyInitializerField = typeBuilder.DefineField("__lazyInitializer", LazyInitializerType, FieldAttributes.Private);
            var proxyInfoField       = typeBuilder.DefineField("__proxyInfo", typeof(NHibernateProxyFactoryInfo), FieldAttributes.Private);

            ImplementConstructor(typeBuilder, parentType, lazyInitializerField, proxyInfoField);

            // Provide a custom implementation of ISerializable instead of redirecting it back to the interceptor
            foreach (var method in ProxyBuilderHelper.GetProxiableMethods(baseType, interfaces.Except(new[] { typeof(ISerializable) })))
            {
                CreateProxiedMethod(typeBuilder, method, lazyInitializerField, parentType);
            }

            ProxyBuilderHelper.MakeProxySerializable(typeBuilder);
            ImplementDeserializationConstructor(typeBuilder, parentType);
            ImplementGetObjectData(typeBuilder, proxyInfoField, lazyInitializerField);

            var proxyType = typeBuilder.CreateTypeInfo();

            ProxyBuilderHelper.Save(assemblyBuilder);

            return(proxyType);
        }
        private static void ImplementGetObjectData(TypeBuilder typeBuilder, FieldInfo proxyInfoField, FieldInfo lazyInitializerField)
        {
            var methodBuilder = ProxyBuilderHelper.GetObjectDataMethodBuilder(typeBuilder);

            var IL = methodBuilder.GetILGenerator();

            // info.SetType(typeof(NHibernateProxyObjectReference));
            IL.Emit(OpCodes.Ldarg_1);
            IL.Emit(OpCodes.Ldtoken, typeof(NHibernateProxyObjectReference));
            IL.Emit(OpCodes.Call, ReflectionCache.TypeMethods.GetTypeFromHandle);
            IL.Emit(OpCodes.Callvirt, ProxyBuilderHelper.SerializationInfoSetTypeMethod);

            // return
            //  (new NHibernateProxyObjectReference(
            //      this.__proxyInfo,
            //      this.__lazyInitializer.Identifier),
            //      this.__lazyInitializer.IsUninitialized ? null : this.__lazyInitializer.GetImplementation())
            //  .GetObjectData(info, context);
            //this.__proxyInfo
            IL.Emit(OpCodes.Ldarg_0);
            IL.Emit(OpCodes.Ldfld, proxyInfoField);

            //this.__lazyInitializer.Identifier
            IL.Emit(OpCodes.Ldarg_0);
            IL.Emit(OpCodes.Ldfld, lazyInitializerField);
            IL.Emit(OpCodes.Callvirt, LazyInitializerIdentifierProperty.GetMethod);

            // this.__lazyInitializer.IsUninitialized ? null : this.__lazyInitializer.GetImplementation()
            var isUnitialized           = IL.DefineLabel();
            var endIsUnitializedTernary = IL.DefineLabel();

            IL.Emit(OpCodes.Ldarg_0);
            IL.Emit(OpCodes.Ldfld, lazyInitializerField);
            IL.Emit(OpCodes.Callvirt, LazyInitializerIsUninitializedProperty.GetMethod);
            IL.Emit(OpCodes.Brtrue, isUnitialized);
            IL.Emit(OpCodes.Ldarg_0);
            IL.Emit(OpCodes.Ldfld, lazyInitializerField);
            IL.Emit(OpCodes.Callvirt, LazyInitializerGetImplementationMethod);
            IL.Emit(OpCodes.Br, endIsUnitializedTernary);
            IL.MarkLabel(isUnitialized);
            IL.Emit(OpCodes.Ldnull);
            IL.MarkLabel(endIsUnitializedTernary);

            var constructor = typeof(NHibernateProxyObjectReference).GetConstructor(
                new[]
            {
                typeof(NHibernateProxyFactoryInfo),
                typeof(object),
                typeof(object)
            });

            IL.Emit(OpCodes.Newobj, constructor);

            IL.Emit(OpCodes.Ldarg_1);
            IL.Emit(OpCodes.Ldarg_2);
            IL.Emit(OpCodes.Callvirt, ProxyBuilderHelper.SerializableGetObjectDataMethod);

            IL.Emit(OpCodes.Ret);

            typeBuilder.DefineMethodOverride(methodBuilder, ProxyBuilderHelper.SerializableGetObjectDataMethod);
        }