From ee06c89ecdbb07b40beefc50a95c2946ed580626 Mon Sep 17 00:00:00 2001 From: Alexander Zaytsev Date: Sun, 3 Dec 2017 21:22:31 +1300 Subject: [PATCH 1/2] Fix ProxyFactory cache - use a correct implementation of cache - reduce number of allocations of ProxyCacheEntry - reduce memory flow --- .../NHSpecificTest/NH3954/EqualsFixture.cs | 15 +-- .../NH3954/ProxyCacheFixture.cs | 34 +++---- src/NHibernate/Async/Engine/Cascade.cs | 2 +- .../DynamicProxy/DefaultMethodEmitter.cs | 22 +---- .../Proxy/DynamicProxy/HashSetExtensions.cs | 5 +- .../Proxy/DynamicProxy/IProxyCache.cs | 5 +- .../Proxy/DynamicProxy/ProxyCache.cs | 20 ++-- .../Proxy/DynamicProxy/ProxyCacheEntry.cs | 35 +++---- .../Proxy/DynamicProxy/ProxyFactory.cs | 96 ++++++------------- 9 files changed, 93 insertions(+), 141 deletions(-) diff --git a/src/NHibernate.Test/NHSpecificTest/NH3954/EqualsFixture.cs b/src/NHibernate.Test/NHSpecificTest/NH3954/EqualsFixture.cs index 51cf0323634..5b1c896da1d 100644 --- a/src/NHibernate.Test/NHSpecificTest/NH3954/EqualsFixture.cs +++ b/src/NHibernate.Test/NHSpecificTest/NH3954/EqualsFixture.cs @@ -1,5 +1,6 @@ using System; using System.Reflection; +using System.Runtime.Serialization; using NHibernate.Proxy; using NHibernate.Proxy.DynamicProxy; using NHibernate.Type; @@ -48,9 +49,9 @@ public void TypeInequality() [Test] public void InterfaceEquality() { - var entry1 = new ProxyCacheEntry(typeof(Entity1), new[] { typeof(INHibernateProxy), typeof(IProxy) }); + var entry1 = new ProxyCacheEntry(typeof(Entity1), new[] { typeof(INHibernateProxy), typeof(ISerializable) }); // Interfaces order inverted on purpose: must be supported. - var entry2 = new ProxyCacheEntry(typeof(Entity1), new[] { typeof(IProxy), typeof(INHibernateProxy) }); + var entry2 = new ProxyCacheEntry(typeof(Entity1), new[] { typeof(ISerializable), typeof(INHibernateProxy) }); Assert.IsTrue(entry1.Equals(entry2)); Assert.IsTrue(entry2.Equals(entry1)); } @@ -59,9 +60,9 @@ public void InterfaceEquality() [Test] public void InterfaceEqualityWithLotOfUnordererdAndDupInterfaces() { - var entry1 = new ProxyCacheEntry(typeof(Entity1), new[] { typeof(INHibernateProxy), typeof(IProxy), typeof(IType), typeof(IDisposable), typeof(IFilter) }); + var entry1 = new ProxyCacheEntry(typeof(Entity1), new[] { typeof(INHibernateProxy), typeof(ISerializable), typeof(IType), typeof(IDisposable), typeof(IFilter) }); // Interfaces order inverted and duplicated on purpose: must be supported. - var entry2 = new ProxyCacheEntry(typeof(Entity1), new[] { typeof(IType), typeof(IProxy), typeof(IFilter), typeof(IDisposable), typeof(IType), typeof(IFilter), typeof(INHibernateProxy) }); + var entry2 = new ProxyCacheEntry(typeof(Entity1), new[] { typeof(IType), typeof(ISerializable), typeof(IFilter), typeof(IDisposable), typeof(IType), typeof(IFilter), typeof(INHibernateProxy) }); Assert.IsTrue(entry1.Equals(entry2)); Assert.IsTrue(entry2.Equals(entry1)); } @@ -69,11 +70,11 @@ public void InterfaceEqualityWithLotOfUnordererdAndDupInterfaces() [Test] public void InterfaceInequality() { - var entry1 = new ProxyCacheEntry(typeof(Entity1), new[] { typeof(INHibernateProxy), typeof(IProxy) }); - var entry2 = new ProxyCacheEntry(typeof(Entity1), new[] { typeof(IProxy) }); + var entry1 = new ProxyCacheEntry(typeof(Entity1), new[] { typeof(INHibernateProxy), typeof(ISerializable) }); + var entry2 = new ProxyCacheEntry(typeof(Entity1), new[] { typeof(ISerializable) }); TweakEntry(entry2, entry1.GetHashCode()); Assert.IsFalse(entry1.Equals(entry2)); Assert.IsFalse(entry2.Equals(entry1)); } } -} \ No newline at end of file +} diff --git a/src/NHibernate.Test/NHSpecificTest/NH3954/ProxyCacheFixture.cs b/src/NHibernate.Test/NHSpecificTest/NH3954/ProxyCacheFixture.cs index 5692f49fc8f..0583f96a0b1 100644 --- a/src/NHibernate.Test/NHSpecificTest/NH3954/ProxyCacheFixture.cs +++ b/src/NHibernate.Test/NHSpecificTest/NH3954/ProxyCacheFixture.cs @@ -1,34 +1,36 @@ -using System.Collections.Concurrent; +using System; +using System.Collections.Concurrent; using System.Reflection; +using System.Runtime.Serialization; using NHibernate.Proxy; using NHibernate.Proxy.DynamicProxy; using NUnit.Framework; namespace NHibernate.Test.NHSpecificTest.NH3954 { - [TestFixture, Explicit("Demonstrates bug impact on cache, but which tests will fail is a bit unpredictable")] + [TestFixture, Explicit("Demonstrates bug impact on cache, but which tests will fail is a bit unpredictable"), Obsolete] public class ProxyCacheFixture { private ProxyCache _cache; - private ConcurrentDictionary _internalCache; + private ConcurrentDictionary _internalCache; private int _hashCode1; private int _hashCode2; private static readonly FieldInfo InternalCacheField = - typeof(ProxyCache).GetField("cache", BindingFlags.Static | BindingFlags.NonPublic); + typeof(ProxyFactory).GetField("_cache", BindingFlags.Static | BindingFlags.NonPublic); [SetUp] public void SetUp() { _cache = new ProxyCache(); - _internalCache = (ConcurrentDictionary)InternalCacheField.GetValue(null); + _internalCache = (ConcurrentDictionary)InternalCacheField.GetValue(null); _cache.StoreProxyType(typeof(Entity1FakeProxy).GetTypeInfo(), typeof(Entity1)); _cache.StoreProxyType(typeof(Entity2FakeProxy).GetTypeInfo(), typeof(Entity2), typeof(INHibernateProxy)); _cache.StoreProxyType(typeof(Entity3FakeProxy).GetTypeInfo(), typeof(Entity3)); - _cache.StoreProxyType(typeof(Entity4FakeProxy).GetTypeInfo(), typeof(Entity4), typeof(IProxy)); - _cache.StoreProxyType(typeof(Entity5FakeProxy).GetTypeInfo(), typeof(Entity5), typeof(INHibernateProxy), typeof(IProxy)); + _cache.StoreProxyType(typeof(Entity4FakeProxy).GetTypeInfo(), typeof(Entity4), typeof(ISerializable)); + _cache.StoreProxyType(typeof(Entity5FakeProxy).GetTypeInfo(), typeof(Entity5), typeof(INHibernateProxy), typeof(ISerializable)); // Artificially inject other entries with same hashcodes _hashCode1 = new ProxyCacheEntry(typeof(Entity1), null).GetHashCode(); @@ -37,14 +39,14 @@ public void SetUp() _hashCode2 = new ProxyCacheEntry(typeof(Entity2), new[] { typeof(INHibernateProxy) }).GetHashCode(); Inject(new ProxyCacheEntry(typeof(Entity2), null), _hashCode2, typeof(Entity2FakeProxy2)); - Inject(new ProxyCacheEntry(typeof(Entity4), new[] { typeof(IProxy) }), _hashCode2, typeof(Entity4FakeProxy2)); - Inject(new ProxyCacheEntry(typeof(Entity5), new[] { typeof(INHibernateProxy), typeof(IProxy) }), _hashCode2, typeof(Entity5FakeProxy2)); + Inject(new ProxyCacheEntry(typeof(Entity4), new[] { typeof(ISerializable) }), _hashCode2, typeof(Entity4FakeProxy2)); + Inject(new ProxyCacheEntry(typeof(Entity5), new[] { typeof(INHibernateProxy), typeof(ISerializable) }), _hashCode2, typeof(Entity5FakeProxy2)); } private void Inject(ProxyCacheEntry entryToTweak, int hashcode, System.Type result) { TweakEntry(entryToTweak, hashcode); - _internalCache[entryToTweak] = result; + _internalCache[entryToTweak] = result.GetTypeInfo(); } private static readonly FieldInfo HashCodeField = @@ -112,14 +114,14 @@ public void ProxyCacheEntity3FakeProxy2() [Test] public void ProxyCacheEntity4FakeProxy() { - var result = _cache.GetProxyType(typeof(Entity4), typeof(IProxy)); + var result = _cache.GetProxyType(typeof(Entity4), typeof(ISerializable)); Assert.AreEqual(typeof(Entity4FakeProxy), result); } [Test] public void ProxyCacheEntity4FakeProxy2() { - var entry = new ProxyCacheEntry(typeof(Entity4), new[] { typeof(IProxy) }); + var entry = new ProxyCacheEntry(typeof(Entity4), new[] { typeof(ISerializable) }); TweakEntry(entry, _hashCode2); var result = _internalCache[entry]; Assert.AreEqual(typeof(Entity4FakeProxy2), result); @@ -128,7 +130,7 @@ public void ProxyCacheEntity4FakeProxy2() [Test] public void ProxyCacheEntity5FakeProxy() { - var result = _cache.GetProxyType(typeof(Entity5), typeof(IProxy), typeof(INHibernateProxy)); + var result = _cache.GetProxyType(typeof(Entity5), typeof(ISerializable), typeof(INHibernateProxy)); Assert.AreEqual(typeof(Entity5FakeProxy), result); } @@ -136,7 +138,7 @@ public void ProxyCacheEntity5FakeProxy() public void ProxyCacheEntity5FakeProxy2() { // Interfaces order inverted on purpose: must be supported. - var entry = new ProxyCacheEntry(typeof(Entity5), new[] { typeof(IProxy), typeof(INHibernateProxy) }); + var entry = new ProxyCacheEntry(typeof(Entity5), new[] { typeof(ISerializable), typeof(INHibernateProxy) }); TweakEntry(entry, _hashCode2); var result = _internalCache[entry]; Assert.AreEqual(typeof(Entity5FakeProxy2), result); @@ -149,7 +151,7 @@ public void ProxyCacheNone() // (Otherwise the test may starts failing unexpectedly sometimes, as the original bug ...) // This one was not added in anyway. TypeInfo result; - Assert.IsFalse(_cache.TryGetProxyType(typeof(Entity2), new[] { typeof(IProxy) }, out result)); + Assert.IsFalse(_cache.TryGetProxyType(typeof(Entity2), new[] { typeof(ISerializable) }, out result)); } } -} \ No newline at end of file +} diff --git a/src/NHibernate/Async/Engine/Cascade.cs b/src/NHibernate/Async/Engine/Cascade.cs index b56d9d18ad6..1ccc4ef3bfc 100644 --- a/src/NHibernate/Async/Engine/Cascade.cs +++ b/src/NHibernate/Async/Engine/Cascade.cs @@ -9,7 +9,7 @@ using System.Collections; - +using System.Collections.Generic; using NHibernate.Collection; using NHibernate.Event; using NHibernate.Persister.Collection; diff --git a/src/NHibernate/Proxy/DynamicProxy/DefaultMethodEmitter.cs b/src/NHibernate/Proxy/DynamicProxy/DefaultMethodEmitter.cs index 48f64bbd14b..7433f00072c 100644 --- a/src/NHibernate/Proxy/DynamicProxy/DefaultMethodEmitter.cs +++ b/src/NHibernate/Proxy/DynamicProxy/DefaultMethodEmitter.cs @@ -10,15 +10,12 @@ using System.Diagnostics; using System.Reflection; using System.Reflection.Emit; -using NHibernate.Linq; using NHibernate.Util; namespace NHibernate.Proxy.DynamicProxy { internal class DefaultMethodEmitter : IMethodBodyEmitter { - private static readonly MethodInfo getInterceptor; - private static readonly MethodInfo handlerMethod = ReflectHelper.GetMethod( i => i.Intercept(null)); private static readonly MethodInfo getArguments = typeof(InvocationInfo).GetMethod("get_Arguments"); @@ -33,17 +30,8 @@ internal class DefaultMethodEmitter : IMethodBodyEmitter typeof (object[]) }); - private static readonly PropertyInfo interceptorProperty = typeof (IProxy).GetProperty("Interceptor"); - - private static readonly ConstructorInfo notImplementedConstructor = typeof(NotImplementedException).GetConstructor(new System.Type[0]); - private readonly IArgumentHandler _argumentHandler; - static DefaultMethodEmitter() - { - getInterceptor = interceptorProperty.GetGetMethod(); - } - public DefaultMethodEmitter() : this(new DefaultArgumentHandler()) {} public DefaultMethodEmitter(IArgumentHandler argumentHandler) @@ -60,12 +48,12 @@ public void EmitMethodBody(MethodBuilder proxyMethod, MethodBuilder callbackMeth ParameterInfo[] parameters = method.GetParameters(); IL.DeclareLocal(typeof (object[])); IL.DeclareLocal(typeof (InvocationInfo)); - IL.DeclareLocal(typeof(System.Type[])); + IL.DeclareLocal(typeof (System.Type[])); IL.Emit(OpCodes.Ldarg_0); - IL.Emit(OpCodes.Callvirt, getInterceptor); + IL.Emit(OpCodes.Ldfld, field); - // if (interceptor == null) + // if (this.__interceptor == null) // return base.method(...); Label skipBaseCall = IL.DefineLabel(); @@ -90,9 +78,9 @@ public void EmitMethodBody(MethodBuilder proxyMethod, MethodBuilder callbackMeth IL.Emit(OpCodes.Newobj, infoConstructor); IL.Emit(OpCodes.Stloc_1); - // this.Interceptor.Intercept(info); + // this.__interceptor.Intercept(info); IL.Emit(OpCodes.Ldarg_0); - IL.Emit(OpCodes.Callvirt, getInterceptor); + IL.Emit(OpCodes.Ldfld, field); IL.Emit(OpCodes.Ldloc_1); IL.Emit(OpCodes.Callvirt, handlerMethod); diff --git a/src/NHibernate/Proxy/DynamicProxy/HashSetExtensions.cs b/src/NHibernate/Proxy/DynamicProxy/HashSetExtensions.cs index 681d0ee2074..92b96f92e8d 100644 --- a/src/NHibernate/Proxy/DynamicProxy/HashSetExtensions.cs +++ b/src/NHibernate/Proxy/DynamicProxy/HashSetExtensions.cs @@ -1,9 +1,12 @@ +using System; using System.Collections.Generic; namespace NHibernate.Proxy.DynamicProxy { + [Obsolete("This class is not used anymore and will be removed in a next major version")] public static class HashSetExtensions { + [Obsolete("This method is not used anymore and will be removed in a next major version")] public static HashSet Merge(this HashSet source, IEnumerable toMerge) { foreach (T item in toMerge) @@ -13,4 +16,4 @@ public static HashSet Merge(this HashSet source, IEnumerable toMerge return source; } } -} \ No newline at end of file +} diff --git a/src/NHibernate/Proxy/DynamicProxy/IProxyCache.cs b/src/NHibernate/Proxy/DynamicProxy/IProxyCache.cs index 8a86d1cb3e0..c816c7b8181 100644 --- a/src/NHibernate/Proxy/DynamicProxy/IProxyCache.cs +++ b/src/NHibernate/Proxy/DynamicProxy/IProxyCache.cs @@ -11,13 +11,16 @@ namespace NHibernate.Proxy.DynamicProxy { + //Since v5.1 + [Obsolete("This class is not used anymore and will be removed in a next major version")] public interface IProxyCache { bool Contains(System.Type baseType, params System.Type[] baseInterfaces); + TypeInfo GetProxyType(System.Type baseType, params System.Type[] baseInterfaces); bool TryGetProxyType(System.Type baseType, System.Type[] baseInterfaces, out TypeInfo proxyType); void StoreProxyType(TypeInfo result, System.Type baseType, params System.Type[] baseInterfaces); } -} \ No newline at end of file +} diff --git a/src/NHibernate/Proxy/DynamicProxy/ProxyCache.cs b/src/NHibernate/Proxy/DynamicProxy/ProxyCache.cs index f6588df3364..546bd5a9809 100644 --- a/src/NHibernate/Proxy/DynamicProxy/ProxyCache.cs +++ b/src/NHibernate/Proxy/DynamicProxy/ProxyCache.cs @@ -6,32 +6,28 @@ #endregion -using System.Collections.Concurrent; +using System; using System.Reflection; namespace NHibernate.Proxy.DynamicProxy { + //Since v5.1 + [Obsolete("This class is not used anymore and will be removed in a next major version")] public class ProxyCache : IProxyCache { - private static readonly ConcurrentDictionary cache = new ConcurrentDictionary(); - - #region IProxyCache Members - public bool Contains(System.Type baseType, params System.Type[] baseInterfaces) { if (baseType == null) - { return false; - } var entry = new ProxyCacheEntry(baseType, baseInterfaces); - return cache.ContainsKey(entry); + return ProxyFactory._cache.ContainsKey(entry); } public TypeInfo GetProxyType(System.Type baseType, params System.Type[] baseInterfaces) { var entry = new ProxyCacheEntry(baseType, baseInterfaces); - return cache[entry]; + return ProxyFactory._cache[entry]; } public bool TryGetProxyType(System.Type baseType, System.Type[] baseInterfaces, out TypeInfo proxyType) @@ -42,15 +38,13 @@ public bool TryGetProxyType(System.Type baseType, System.Type[] baseInterfaces, return false; var entry = new ProxyCacheEntry(baseType, baseInterfaces); - return cache.TryGetValue(entry, out proxyType); + return ProxyFactory._cache.TryGetValue(entry, out proxyType); } public void StoreProxyType(TypeInfo result, System.Type baseType, params System.Type[] baseInterfaces) { var entry = new ProxyCacheEntry(baseType, baseInterfaces); - cache[entry] = result; + ProxyFactory._cache[entry] = result; } - - #endregion } } diff --git a/src/NHibernate/Proxy/DynamicProxy/ProxyCacheEntry.cs b/src/NHibernate/Proxy/DynamicProxy/ProxyCacheEntry.cs index e3e69fe0fa9..e8118925729 100644 --- a/src/NHibernate/Proxy/DynamicProxy/ProxyCacheEntry.cs +++ b/src/NHibernate/Proxy/DynamicProxy/ProxyCacheEntry.cs @@ -8,29 +8,32 @@ using System; using System.Collections.Generic; +using System.Linq; namespace NHibernate.Proxy.DynamicProxy { public class ProxyCacheEntry : IEquatable { private readonly int _hashCode; + private readonly HashSet _uniqueInterfaces; public ProxyCacheEntry(System.Type baseType, System.Type[] interfaces) { - if (baseType == null) - throw new ArgumentNullException(nameof(baseType)); - BaseType = baseType; - _uniqueInterfaces = new HashSet(interfaces ?? new System.Type[0]); + BaseType = baseType ?? throw new ArgumentNullException(nameof(baseType)); - if (_uniqueInterfaces.Count == 0) + var uniqueInterfaces = new HashSet(); + if (interfaces != null && interfaces.Length > 0) { - _hashCode = baseType.GetHashCode(); - return; + uniqueInterfaces.UnionWith(interfaces.Where(i => i != null)); } - - var allTypes = new List(_uniqueInterfaces) { baseType }; - _hashCode = 59; - foreach (System.Type type in allTypes) + _uniqueInterfaces = uniqueInterfaces; + + _hashCode = 59 ^ baseType.GetHashCode(); + + if (_uniqueInterfaces.Count == 0) + return; + + foreach (var type in _uniqueInterfaces) { // This simple implementation is nonsensitive to list order. If changing it for a sensitive one, // take care of ordering the list. @@ -39,14 +42,12 @@ public ProxyCacheEntry(System.Type baseType, System.Type[] interfaces) } public System.Type BaseType { get; } - public IReadOnlyCollection Interfaces { get { return _uniqueInterfaces; } } - - private HashSet _uniqueInterfaces; + + public IReadOnlyCollection Interfaces => _uniqueInterfaces; public override bool Equals(object obj) { - var that = obj as ProxyCacheEntry; - return Equals(that); + return Equals(obj as ProxyCacheEntry); } public bool Equals(ProxyCacheEntry other) @@ -64,4 +65,4 @@ public bool Equals(ProxyCacheEntry other) public override int GetHashCode() => _hashCode; } -} \ No newline at end of file +} diff --git a/src/NHibernate/Proxy/DynamicProxy/ProxyFactory.cs b/src/NHibernate/Proxy/DynamicProxy/ProxyFactory.cs index 7ac74dbf668..4f35eb0d35a 100644 --- a/src/NHibernate/Proxy/DynamicProxy/ProxyFactory.cs +++ b/src/NHibernate/Proxy/DynamicProxy/ProxyFactory.cs @@ -7,18 +7,20 @@ #endregion using System; +using System.Collections.Concurrent; using System.Collections.Generic; using System.Linq; using System.Reflection; using System.Reflection.Emit; using System.Runtime.Serialization; -using NHibernate.Linq; using NHibernate.Util; namespace NHibernate.Proxy.DynamicProxy { public sealed class ProxyFactory { + internal static readonly ConcurrentDictionary _cache = new ConcurrentDictionary(); + private static readonly ConstructorInfo defaultBaseConstructor = typeof(object).GetConstructor(new System.Type[0]); private static readonly MethodInfo getValue = ReflectHelper.GetMethod( @@ -35,24 +37,21 @@ public ProxyFactory(IProxyAssemblyBuilder proxyAssemblyBuilder) : this(new DefaultyProxyMethodBuilder(), proxyAssemblyBuilder) {} public ProxyFactory(IProxyMethodBuilder proxyMethodBuilder) - : this(new DefaultyProxyMethodBuilder(), new DefaultProxyAssemblyBuilder()) {} + : this(proxyMethodBuilder, new DefaultProxyAssemblyBuilder()) {} public ProxyFactory(IProxyMethodBuilder proxyMethodBuilder, IProxyAssemblyBuilder proxyAssemblyBuilder) { - if (proxyMethodBuilder == null) - { - throw new ArgumentNullException("proxyMethodBuilder"); - } - ProxyMethodBuilder = proxyMethodBuilder; + ProxyMethodBuilder = proxyMethodBuilder ?? throw new ArgumentNullException(nameof(proxyMethodBuilder)); ProxyAssemblyBuilder = proxyAssemblyBuilder; - Cache = new ProxyCache(); } - public IProxyCache Cache { get; private set; } + //Since v5.1 + [Obsolete("This property is not used anymore and will be removed in a next major version")] + public IProxyCache Cache { get; } = new ProxyCache(); - public IProxyMethodBuilder ProxyMethodBuilder { get; private set; } + public IProxyMethodBuilder ProxyMethodBuilder { get; } - public IProxyAssemblyBuilder ProxyAssemblyBuilder { get; private set; } + public IProxyAssemblyBuilder ProxyAssemblyBuilder { get; } public object CreateProxy(System.Type instanceType, IInterceptor interceptor, params System.Type[] baseInterfaces) { @@ -60,37 +59,21 @@ public object CreateProxy(System.Type instanceType, IInterceptor interceptor, pa object result = Activator.CreateInstance(proxyType); var proxy = (IProxy) result; proxy.Interceptor = interceptor; - return result; } public System.Type CreateProxyType(System.Type baseType, params System.Type[] interfaces) { - System.Type[] baseInterfaces = ReferenceEquals(null, interfaces) ? new System.Type[0] : interfaces.Where(t => t != null).ToArray(); - - TypeInfo proxyTypeInfo; + if (baseType == null) throw new ArgumentNullException(nameof(baseType)); - // Reuse the previous results, if possible, Fast path without locking. - if (Cache.TryGetProxyType(baseType, baseInterfaces, out proxyTypeInfo)) - return proxyTypeInfo; + var typeFactory = _cache.GetOrAdd( + new ProxyCacheEntry(baseType, interfaces), + k => CreateUncachedProxyType(k.BaseType, k.Interfaces)); - lock (Cache) - { - // Recheck in case we got interrupted. - if (!Cache.TryGetProxyType(baseType, baseInterfaces, out proxyTypeInfo)) - { - proxyTypeInfo = CreateUncachedProxyType(baseType, baseInterfaces); - - // Cache the proxy type - if (proxyTypeInfo != null && Cache != null) - Cache.StoreProxyType(proxyTypeInfo, baseType, baseInterfaces); - } - - return proxyTypeInfo; - } + return typeFactory; } - private TypeInfo CreateUncachedProxyType(System.Type baseType, System.Type[] baseInterfaces) + private TypeInfo CreateUncachedProxyType(System.Type baseType, IReadOnlyCollection baseInterfaces) { AppDomain currentDomain = AppDomain.CurrentDomain; string typeName = string.Format("{0}Proxy", baseType.Name); @@ -102,10 +85,11 @@ private TypeInfo CreateUncachedProxyType(System.Type baseType, System.Type[] bas ModuleBuilder moduleBuilder = ProxyAssemblyBuilder.DefineDynamicModule(assemblyBuilder, moduleName); TypeAttributes typeAttributes = TypeAttributes.AutoClass | TypeAttributes.Class | - TypeAttributes.Public | TypeAttributes.BeforeFieldInit; + TypeAttributes.Public | TypeAttributes.BeforeFieldInit; var interfaces = new HashSet(); - interfaces.Merge(baseInterfaces); + interfaces.UnionWith(baseInterfaces); + interfaces.UnionWith(baseInterfaces.SelectMany(i => i.GetInterfaces())); // Use the proxy dummy as the base type // since we're not inheriting from any class type @@ -115,13 +99,7 @@ private TypeInfo CreateUncachedProxyType(System.Type baseType, System.Type[] bas parentType = typeof (ProxyDummy); interfaces.Add(baseType); } - - // Add any inherited interfaces - System.Type[] computedInterfaces = interfaces.ToArray(); - foreach (System.Type interfaceType in computedInterfaces) - { - interfaces.Merge(GetInterfaces(interfaceType)); - } + interfaces.UnionWith(baseType.GetInterfaces()); // Add the ISerializable interface so that it can be implemented interfaces.Add(typeof (ISerializable)); @@ -151,32 +129,14 @@ private TypeInfo CreateUncachedProxyType(System.Type baseType, System.Type[] bas return proxyType; } - private IEnumerable GetInterfaces(System.Type currentType) - { - return GetAllInterfaces(currentType); - } - - private IEnumerable GetAllInterfaces(System.Type currentType) - { - System.Type[] interfaces = currentType.GetInterfaces(); - - foreach (System.Type current in interfaces) - { - yield return current; - foreach (System.Type @interface in GetAllInterfaces(current)) - { - yield return @interface; - } - } - } - private IEnumerable GetProxiableMethods(System.Type type, IEnumerable interfaces) { const BindingFlags candidateMethodsBindingFlags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance; - return + return type.GetMethods(candidateMethodsBindingFlags) - .Where(method=> method.IsProxiable()) - .Concat(interfaces.SelectMany(interfaceType => interfaceType.GetMethods())).Distinct(); + .Where(method => method.IsProxiable()) + .Concat(interfaces.SelectMany(interfaceType => interfaceType.GetMethods())) + .Distinct(); } private static ConstructorBuilder DefineConstructor(TypeBuilder typeBuilder, System.Type parentType) @@ -206,7 +166,7 @@ private static ConstructorBuilder DefineConstructor(TypeBuilder typeBuilder, Sys return constructor; } - private static void ImplementGetObjectData(System.Type baseType, System.Type[] baseInterfaces, TypeBuilder typeBuilder, FieldInfo interceptorField) + private static void ImplementGetObjectData(System.Type baseType, IReadOnlyCollection baseInterfaces, TypeBuilder typeBuilder, FieldInfo interceptorField) { const MethodAttributes attributes = MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.Virtual; @@ -236,7 +196,7 @@ private static void ImplementGetObjectData(System.Type baseType, System.Type[] b IL.Emit(OpCodes.Ldstr, baseType.AssemblyQualifiedName); IL.Emit(OpCodes.Callvirt, addValue); - int baseInterfaceCount = baseInterfaces.Length; + int baseInterfaceCount = baseInterfaces.Count; // Save the number of base interfaces IL.Emit(OpCodes.Ldarg_1); @@ -294,7 +254,7 @@ private static void DefineSerializationConstructor(TypeBuilder typeBuilder, Fiel IL.Emit(OpCodes.Ret); } - private static void AddSerializationSupport(System.Type baseType, System.Type[] baseInterfaces, TypeBuilder typeBuilder, FieldInfo interceptorField, ConstructorBuilder defaultConstructor) + private static void AddSerializationSupport(System.Type baseType, IReadOnlyCollection baseInterfaces, TypeBuilder typeBuilder, FieldInfo interceptorField, ConstructorBuilder defaultConstructor) { ConstructorInfo serializableConstructor = typeof(SerializableAttribute).GetConstructor(new System.Type[0]); var customAttributeBuilder = new CustomAttributeBuilder(serializableConstructor, new object[0]); @@ -304,4 +264,4 @@ private static void AddSerializationSupport(System.Type baseType, System.Type[] ImplementGetObjectData(baseType, baseInterfaces, typeBuilder, interceptorField); } } -} \ No newline at end of file +} From 7e64752d29893b5559ce04786f5b88bbff50600e Mon Sep 17 00:00:00 2001 From: Alexander Zaytsev Date: Wed, 6 Dec 2017 09:47:39 +1300 Subject: [PATCH 2/2] Update IProxyCache.cs --- src/NHibernate/Proxy/DynamicProxy/IProxyCache.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NHibernate/Proxy/DynamicProxy/IProxyCache.cs b/src/NHibernate/Proxy/DynamicProxy/IProxyCache.cs index c816c7b8181..cf3e6654941 100644 --- a/src/NHibernate/Proxy/DynamicProxy/IProxyCache.cs +++ b/src/NHibernate/Proxy/DynamicProxy/IProxyCache.cs @@ -12,7 +12,7 @@ namespace NHibernate.Proxy.DynamicProxy { //Since v5.1 - [Obsolete("This class is not used anymore and will be removed in a next major version")] + [Obsolete("This interface is not used anymore and will be removed in a next major version")] public interface IProxyCache { bool Contains(System.Type baseType, params System.Type[] baseInterfaces);