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);
        }
        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);
        }