From af5a14055abeb3a982bb726a292298f982548607 Mon Sep 17 00:00:00 2001 From: Sergei Pavlov Date: Mon, 18 Mar 2024 11:32:18 -0700 Subject: [PATCH 1/4] Optimization: Memoize `RequiredMemberAttribute` search --- .../Reflection/ReflectionActivator.cs | 20 ++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/src/Autofac/Core/Activators/Reflection/ReflectionActivator.cs b/src/Autofac/Core/Activators/Reflection/ReflectionActivator.cs index 1c0ad351c..6cc42c098 100644 --- a/src/Autofac/Core/Activators/Reflection/ReflectionActivator.cs +++ b/src/Autofac/Core/Activators/Reflection/ReflectionActivator.cs @@ -1,6 +1,7 @@ // Copyright (c) Autofac Project. All rights reserved. // Licensed under the MIT License. See LICENSE in the project root for license information. +using System.Collections.Concurrent; using System.Globalization; using System.Reflection; using System.Runtime.CompilerServices; @@ -19,6 +20,10 @@ namespace Autofac.Core.Activators.Reflection; [SuppressMessage("Microsoft.Design", "CA1063:ImplementIDisposableCorrectly", Justification = "There is nothing in the derived class to dispose so no override is necessary.")] public class ReflectionActivator : InstanceActivator, IInstanceActivator { +#if NET7_0_OR_GREATER + private static readonly ConcurrentDictionary IsRequiredMemberByType = new(); +#endif + private readonly Type _implementationType; private readonly Parameter[] _configuredProperties; private readonly Parameter[] _defaultParameters; @@ -86,17 +91,18 @@ public void ConfigurePipeline(IComponentRegistryServices componentRegistryServic #if NET7_0_OR_GREATER // The RequiredMemberAttribute has Inherit = false on its AttributeUsage options, // so we can't use the expected GetCustomAttribute(inherit: true) option, and must walk the tree. - var currentType = _implementationType; - while (currentType is not null && !currentType.Equals(typeof(object))) + _anyRequiredMembers = IsRequiredMemberByType.GetOrAdd(_implementationType, static t => { - if (currentType.GetCustomAttribute() is not null) + for (var currentType = t; currentType is not null && !currentType.Equals(typeof(object)); currentType = currentType.BaseType) { - _anyRequiredMembers = true; - break; + if (currentType.GetCustomAttribute() is not null) + { + return true; + } } - currentType = currentType.BaseType; - } + return false; + }); #else _anyRequiredMembers = false; #endif From 12ebdf4ccd6ef13bf8a7c4766b9fea31307003c2 Mon Sep 17 00:00:00 2001 From: Sergei Pavlov Date: Mon, 18 Mar 2024 11:58:13 -0700 Subject: [PATCH 2/4] Make Dictionary with string key to process Unloading module correctly --- .../Reflection/ReflectionActivator.cs | 21 +++++++++++-------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/src/Autofac/Core/Activators/Reflection/ReflectionActivator.cs b/src/Autofac/Core/Activators/Reflection/ReflectionActivator.cs index 6cc42c098..016402c0b 100644 --- a/src/Autofac/Core/Activators/Reflection/ReflectionActivator.cs +++ b/src/Autofac/Core/Activators/Reflection/ReflectionActivator.cs @@ -21,7 +21,7 @@ namespace Autofac.Core.Activators.Reflection; public class ReflectionActivator : InstanceActivator, IInstanceActivator { #if NET7_0_OR_GREATER - private static readonly ConcurrentDictionary IsRequiredMemberByType = new(); + private static readonly ConcurrentDictionary IsRequiredMemberByTypeName = new(); #endif private readonly Type _implementationType; @@ -91,18 +91,21 @@ public void ConfigurePipeline(IComponentRegistryServices componentRegistryServic #if NET7_0_OR_GREATER // The RequiredMemberAttribute has Inherit = false on its AttributeUsage options, // so we can't use the expected GetCustomAttribute(inherit: true) option, and must walk the tree. - _anyRequiredMembers = IsRequiredMemberByType.GetOrAdd(_implementationType, static t => - { - for (var currentType = t; currentType is not null && !currentType.Equals(typeof(object)); currentType = currentType.BaseType) + _anyRequiredMembers = IsRequiredMemberByTypeName.GetOrAdd( + _implementationType.FullName!, + static (_, t) => { - if (currentType.GetCustomAttribute() is not null) + for (var currentType = t; currentType is not null && !currentType.Equals(typeof(object)); currentType = currentType.BaseType) { - return true; + if (currentType.GetCustomAttribute() is not null) + { + return true; + } } - } - return false; - }); + return false; + }, + _implementationType); #else _anyRequiredMembers = false; #endif From 679f8388ed6fb7c4e5f6ed25c3004db8c799caf2 Mon Sep 17 00:00:00 2001 From: Sergei Pavlov Date: Mon, 18 Mar 2024 13:17:07 -0700 Subject: [PATCH 3/4] Use `ReflectionCacheSet` --- .../Activators/Reflection/ReflectionActivator.cs | 16 +++++----------- src/Autofac/Core/InternalReflectionCaches.cs | 10 ++++++++++ 2 files changed, 15 insertions(+), 11 deletions(-) diff --git a/src/Autofac/Core/Activators/Reflection/ReflectionActivator.cs b/src/Autofac/Core/Activators/Reflection/ReflectionActivator.cs index 016402c0b..5b43420fa 100644 --- a/src/Autofac/Core/Activators/Reflection/ReflectionActivator.cs +++ b/src/Autofac/Core/Activators/Reflection/ReflectionActivator.cs @@ -1,7 +1,6 @@ // Copyright (c) Autofac Project. All rights reserved. // Licensed under the MIT License. See LICENSE in the project root for license information. -using System.Collections.Concurrent; using System.Globalization; using System.Reflection; using System.Runtime.CompilerServices; @@ -20,10 +19,6 @@ namespace Autofac.Core.Activators.Reflection; [SuppressMessage("Microsoft.Design", "CA1063:ImplementIDisposableCorrectly", Justification = "There is nothing in the derived class to dispose so no override is necessary.")] public class ReflectionActivator : InstanceActivator, IInstanceActivator { -#if NET7_0_OR_GREATER - private static readonly ConcurrentDictionary IsRequiredMemberByTypeName = new(); -#endif - private readonly Type _implementationType; private readonly Parameter[] _configuredProperties; private readonly Parameter[] _defaultParameters; @@ -91,11 +86,11 @@ public void ConfigurePipeline(IComponentRegistryServices componentRegistryServic #if NET7_0_OR_GREATER // The RequiredMemberAttribute has Inherit = false on its AttributeUsage options, // so we can't use the expected GetCustomAttribute(inherit: true) option, and must walk the tree. - _anyRequiredMembers = IsRequiredMemberByTypeName.GetOrAdd( - _implementationType.FullName!, - static (_, t) => + _anyRequiredMembers = ReflectionCacheSet.Shared.Internal.HasRequiredMemberAttribute.GetOrAdd( + _implementationType, + static t => { - for (var currentType = t; currentType is not null && !currentType.Equals(typeof(object)); currentType = currentType.BaseType) + for (var currentType = t; currentType is not null && currentType != typeof(object); currentType = currentType.BaseType) { if (currentType.GetCustomAttribute() is not null) { @@ -104,8 +99,7 @@ public void ConfigurePipeline(IComponentRegistryServices componentRegistryServic } return false; - }, - _implementationType); + }); #else _anyRequiredMembers = false; #endif diff --git a/src/Autofac/Core/InternalReflectionCaches.cs b/src/Autofac/Core/InternalReflectionCaches.cs index a3fb78e94..1597ecc26 100644 --- a/src/Autofac/Core/InternalReflectionCaches.cs +++ b/src/Autofac/Core/InternalReflectionCaches.cs @@ -54,6 +54,13 @@ internal class InternalReflectionCaches /// public ReflectionCacheDictionary DefaultPublicConstructors { get; } +#if NET7_0_OR_GREATER + /// + /// Gets a cache used by . + /// + public ReflectionCacheDictionary HasRequiredMemberAttribute { get; } +#endif + /// /// Initializes a new instance of the class. /// @@ -72,5 +79,8 @@ public InternalReflectionCaches(ReflectionCacheSet set) AutowiringPropertySetters = set.GetOrCreateCache>>(nameof(AutowiringPropertySetters)); AutowiringInjectableProperties = set.GetOrCreateCache>>(nameof(AutowiringInjectableProperties)); DefaultPublicConstructors = set.GetOrCreateCache>(nameof(DefaultPublicConstructors)); +#if NET7_0_OR_GREATER + HasRequiredMemberAttribute = set.GetOrCreateCache>(nameof(HasRequiredMemberAttribute)); +#endif } } From 3fe2ddfd23391fd7edbe5b081ad5fa67ebe0857b Mon Sep 17 00:00:00 2001 From: Sergei Pavlov Date: Mon, 18 Mar 2024 13:20:25 -0700 Subject: [PATCH 4/4] Remove trailing whitespace --- src/Autofac/Core/InternalReflectionCaches.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Autofac/Core/InternalReflectionCaches.cs b/src/Autofac/Core/InternalReflectionCaches.cs index bfe6102ea..b1068941d 100644 --- a/src/Autofac/Core/InternalReflectionCaches.cs +++ b/src/Autofac/Core/InternalReflectionCaches.cs @@ -65,7 +65,7 @@ internal class InternalReflectionCaches /// public ReflectionCacheDictionary HasRequiredMemberAttribute { get; } #endif - + /// /// Initializes a new instance of the class. ///