From bfbe682dc814b72eaabc4e353b7ba4eb0c624c91 Mon Sep 17 00:00:00 2001 From: Travis Illig Date: Thu, 18 Sep 2025 09:43:58 -0700 Subject: [PATCH 01/15] Enabled return value documentation and fixed missing docs. --- build/Source.ruleset | 2 -- src/Autofac/Builder/MetadataConfiguration.cs | 3 +++ src/Autofac/ContainerBuilder.cs | 1 + .../Activators/Reflection/BoundConstructor.cs | 4 +++- .../Reflection/BoundConstructorResources.resx | 2 +- .../Reflection/ConstructorBinder.cs | 3 +++ .../BaseGenericResolveDelegateInvoker.cs | 10 ++++++--- .../Core/Resolving/ResolveOperation.cs | 1 + .../Diagnostics/DiagnosticTracerBase.cs | 1 + ...ightweightAdapterRegistrationExtensions.cs | 8 +++---- .../OpenGenericRegistrationExtensions.cs | 8 +++++-- src/Autofac/Features/OwnedInstances/Owned.cs | 5 ++++- src/Autofac/RegistrationExtensions.Adapter.cs | 21 ++++++++----------- .../RegistrationExtensions.Composite.cs | 5 +++++ .../RegistrationExtensions.Decorators.cs | 16 +++++++------- src/Autofac/TypeExtensions.cs | 4 ++-- .../Cache/TypeAssemblyReferenceProvider.cs | 3 +++ src/Autofac/Util/Disposable.cs | 3 ++- src/Autofac/Util/Enforce.cs | 4 ++-- 19 files changed, 65 insertions(+), 39 deletions(-) diff --git a/build/Source.ruleset b/build/Source.ruleset index c0f2a0953..6d30f8bb3 100644 --- a/build/Source.ruleset +++ b/build/Source.ruleset @@ -46,8 +46,6 @@ - - diff --git a/src/Autofac/Builder/MetadataConfiguration.cs b/src/Autofac/Builder/MetadataConfiguration.cs index 56bde0872..ec0918f78 100644 --- a/src/Autofac/Builder/MetadataConfiguration.cs +++ b/src/Autofac/Builder/MetadataConfiguration.cs @@ -29,6 +29,9 @@ public class MetadataConfiguration /// The type of the property. /// An expression that accesses the property to set. /// The property value to set. + /// + /// The current for continued configuration. + /// public MetadataConfiguration For(Expression> propertyAccessor, TProperty value) { if (propertyAccessor == null) diff --git a/src/Autofac/ContainerBuilder.cs b/src/Autofac/ContainerBuilder.cs index 5c08ecd56..5bc5c5950 100644 --- a/src/Autofac/ContainerBuilder.cs +++ b/src/Autofac/ContainerBuilder.cs @@ -105,6 +105,7 @@ internal ContainerBuilder(IDictionary properties, IComponentReg /// /// This is primarily for extending the builder syntax. /// Callback to execute. + /// A that can be used to unregister the callback. public DeferredCallback RegisterCallback(Action configurationCallback) { var c = new DeferredCallback(configurationCallback); diff --git a/src/Autofac/Core/Activators/Reflection/BoundConstructor.cs b/src/Autofac/Core/Activators/Reflection/BoundConstructor.cs index ad323b592..4a7b19452 100644 --- a/src/Autofac/Core/Activators/Reflection/BoundConstructor.cs +++ b/src/Autofac/Core/Activators/Reflection/BoundConstructor.cs @@ -25,6 +25,7 @@ public class BoundConstructor /// The binder that generated this binding. /// The instance factory. /// The set of value-retrieval functions. + /// A with details about the successful bind. [SuppressMessage("Design", "CA1062:Validate arguments of public methods", Justification = "Validated in constructor.")] public static BoundConstructor ForBindSuccess(ConstructorBinder binder, Func factory, Func[] valueRetrievers) => new(binder, factory, valueRetrievers); @@ -34,6 +35,7 @@ public static BoundConstructor ForBindSuccess(ConstructorBinder binder, Func /// The binder that generated this binding. /// The first parameter that prevented binding. + /// A with details about the unsuccessful bind. public static BoundConstructor ForBindFailure(ConstructorBinder binder, ParameterInfo firstNonBindableParameter) => new(binder, firstNonBindableParameter); @@ -101,7 +103,7 @@ public object Instantiate() { if (!CanInstantiate) { - throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, BoundConstructorResources.CannotInstantitate, Description)); + throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, BoundConstructorResources.CannotInstantiate, Description)); } object?[] values; diff --git a/src/Autofac/Core/Activators/Reflection/BoundConstructorResources.resx b/src/Autofac/Core/Activators/Reflection/BoundConstructorResources.resx index 623ac18fb..c6c7b935b 100644 --- a/src/Autofac/Core/Activators/Reflection/BoundConstructorResources.resx +++ b/src/Autofac/Core/Activators/Reflection/BoundConstructorResources.resx @@ -120,7 +120,7 @@ Bound constructor '{0}'. - + The binding cannot be instantiated: {0} diff --git a/src/Autofac/Core/Activators/Reflection/ConstructorBinder.cs b/src/Autofac/Core/Activators/Reflection/ConstructorBinder.cs index 73aa29128..bb1fbab0c 100644 --- a/src/Autofac/Core/Activators/Reflection/ConstructorBinder.cs +++ b/src/Autofac/Core/Activators/Reflection/ConstructorBinder.cs @@ -126,6 +126,9 @@ public BoundConstructor Bind(IEnumerable availableParameters, ICompon /// Get the constructor factory delegate. /// /// Will return null if the constructor contains an invalid parameter. + /// + /// A delegate that can be used to invoke the constructor, or if the constructor is invalid. + /// internal Func? GetConstructorInvoker() { return _factory; diff --git a/src/Autofac/Core/Resolving/BaseGenericResolveDelegateInvoker.cs b/src/Autofac/Core/Resolving/BaseGenericResolveDelegateInvoker.cs index 205844220..88b2cbf9a 100644 --- a/src/Autofac/Core/Resolving/BaseGenericResolveDelegateInvoker.cs +++ b/src/Autofac/Core/Resolving/BaseGenericResolveDelegateInvoker.cs @@ -19,6 +19,9 @@ internal abstract class BaseGenericResolveDelegateInvoker /// /// Method implemented by the derived generated class to get the array for the owned delegate. /// + /// + /// The array for the delegate. + /// protected abstract ParameterInfo[] GetDelegateParameters(); /// @@ -28,8 +31,8 @@ internal abstract class BaseGenericResolveDelegateInvoker /// The type to resolve. /// The context from which to resolve. /// The set of Autofac resolve parameters. - /// The position of the parameter in the - /// delegate's parameter info set. + /// The position of the parameter in the delegate's parameter info set. + /// The resolved value. protected T? ResolveWithParametersOrRegistration(IComponentContext context, IEnumerable parameters, int parameterInfoPosition) where T : notnull { @@ -51,7 +54,8 @@ internal abstract class BaseGenericResolveDelegateInvoker /// /// Checks whether there are any parameters in the set of parameters. /// - /// The parameters. + /// The list of parameters to check. + /// if there are any parameters; otherwise, . [MethodImpl(MethodImplOptions.AggressiveInlining)] protected static bool AnyParameters(IEnumerable parameters) { diff --git a/src/Autofac/Core/Resolving/ResolveOperation.cs b/src/Autofac/Core/Resolving/ResolveOperation.cs index a36ed025f..94b418fc4 100644 --- a/src/Autofac/Core/Resolving/ResolveOperation.cs +++ b/src/Autofac/Core/Resolving/ResolveOperation.cs @@ -42,6 +42,7 @@ public ResolveOperation( /// Execute the complete resolve operation. /// /// The resolution context. + /// The resolved instance. public object Execute(in ResolveRequest request) { return ExecuteOperation(request); diff --git a/src/Autofac/Diagnostics/DiagnosticTracerBase.cs b/src/Autofac/Diagnostics/DiagnosticTracerBase.cs index d68c521c3..5034e137c 100644 --- a/src/Autofac/Diagnostics/DiagnosticTracerBase.cs +++ b/src/Autofac/Diagnostics/DiagnosticTracerBase.cs @@ -191,6 +191,7 @@ protected void DisableBase(string diagnosticName) /// /// The name of the event to check. Diagnostic names are case-sensitive. /// + /// if the observer is enabled for the event; otherwise, . public bool IsEnabled(string diagnosticName) { if (_subscriptions.Count == 0) diff --git a/src/Autofac/Features/LightweightAdapters/LightweightAdapterRegistrationExtensions.cs b/src/Autofac/Features/LightweightAdapters/LightweightAdapterRegistrationExtensions.cs index aecaf3502..9f4591ded 100644 --- a/src/Autofac/Features/LightweightAdapters/LightweightAdapterRegistrationExtensions.cs +++ b/src/Autofac/Features/LightweightAdapters/LightweightAdapterRegistrationExtensions.cs @@ -17,11 +17,10 @@ internal static class LightweightAdapterRegistrationExtensions /// function. /// /// Service type to adapt from. - /// Service type to adapt to. Must not be the - /// same as . + /// Service type to adapt to. Must not be the same as . /// Container builder. - /// Function adapting to - /// service , given the context and parameters. + /// Function adapting to service , given the context and parameters. + /// A registration builder allowing the registration to be further configured. public static IRegistrationBuilder RegisterAdapter( ContainerBuilder builder, @@ -42,6 +41,7 @@ public static IRegistrationBuilder, given the context and parameters. /// Service key or name associated with the components being decorated. /// Service key or name given to the decorated components. + /// The adapter registration for further configuration. public static IRegistrationBuilder RegisterDecorator( ContainerBuilder builder, diff --git a/src/Autofac/Features/OpenGenerics/OpenGenericRegistrationExtensions.cs b/src/Autofac/Features/OpenGenerics/OpenGenericRegistrationExtensions.cs index e9a9c4c1a..b0772758f 100644 --- a/src/Autofac/Features/OpenGenerics/OpenGenericRegistrationExtensions.cs +++ b/src/Autofac/Features/OpenGenerics/OpenGenericRegistrationExtensions.cs @@ -115,8 +115,12 @@ public static IRegistrationBuilderService type being decorated. Must be an open generic type. /// Service key or name associated with the components being decorated. /// Service key or name given to the decorated components. - /// The type of the decorator. Must be an open generic type, and accept a parameter - /// of type , which will be set to the instance being decorated. + /// + /// The type of the decorator. Must be an open generic type, and accept a + /// parameter of type , which will be + /// set to the instance being decorated. + /// + /// The decorator registration for further configuration. public static IRegistrationBuilder RegisterGenericDecorator(ContainerBuilder builder, Type decoratorType, Type decoratedServiceType, object fromKey, object? toKey) { diff --git a/src/Autofac/Features/OwnedInstances/Owned.cs b/src/Autofac/Features/OwnedInstances/Owned.cs index 309454158..040453daa 100644 --- a/src/Autofac/Features/OwnedInstances/Owned.cs +++ b/src/Autofac/Features/OwnedInstances/Owned.cs @@ -104,7 +104,10 @@ protected override void Dispose(bool disposing) /// /// Releases unmanaged and - optionally - managed resources asynchronously. /// - /// true to release both managed and unmanaged resources; false to release only unmanaged resources. + /// + /// to release both managed and unmanaged resources; to release only unmanaged resources. + /// + /// A task to await disposal. protected override async ValueTask DisposeAsync(bool disposing) { if (disposing) diff --git a/src/Autofac/RegistrationExtensions.Adapter.cs b/src/Autofac/RegistrationExtensions.Adapter.cs index 4e8c34556..35b2f9cd0 100644 --- a/src/Autofac/RegistrationExtensions.Adapter.cs +++ b/src/Autofac/RegistrationExtensions.Adapter.cs @@ -19,11 +19,10 @@ public static partial class RegistrationExtensions /// function. /// /// Service type to adapt from. - /// Service type to adapt to. Must not be the - /// same as . + /// Service type to adapt to. Must not be the same as . /// Container builder. - /// Function adapting to - /// service , given the context and parameters. + /// Function adapting to service , given the context and parameters. + /// The adapter registration for continued configuration. public static IRegistrationBuilder RegisterAdapter( this ContainerBuilder builder, @@ -50,11 +49,10 @@ public static IRegistrationBuilder /// Service type to adapt from. - /// Service type to adapt to. Must not be the - /// same as . + /// Service type to adapt to. Must not be the same as . /// Container builder. - /// Function adapting to - /// service , given the context. + /// Function adapting to service , given the context. + /// The adapter registration for continued configuration. public static IRegistrationBuilder RegisterAdapter( this ContainerBuilder builder, @@ -81,11 +79,10 @@ public static IRegistrationBuilder /// Service type to adapt from. - /// Service type to adapt to. Must not be the - /// same as . + /// Service type to adapt to. Must not be the same as . /// Container builder. - /// Function adapting to - /// service . + /// Function adapting to service . + /// The adapter registration for continued configuration. public static IRegistrationBuilder RegisterAdapter( this ContainerBuilder builder, diff --git a/src/Autofac/RegistrationExtensions.Composite.cs b/src/Autofac/RegistrationExtensions.Composite.cs index e3965bd40..cd06df0d4 100644 --- a/src/Autofac/RegistrationExtensions.Composite.cs +++ b/src/Autofac/RegistrationExtensions.Composite.cs @@ -30,6 +30,7 @@ public static partial class RegistrationExtensions /// /// Service type to provide a composite for. /// Container builder. + /// The composite registration for continued configuration. public static IRegistrationBuilder RegisterComposite(this ContainerBuilder builder) where TComposite : notnull, TService where TService : notnull @@ -62,6 +63,7 @@ public static IRegistrationBuilder /// Service type to provide a composite for. + /// The composite registration for continued configuration. public static IRegistrationBuilder RegisterComposite( this ContainerBuilder builder, Type compositeType, @@ -93,6 +95,7 @@ public static IRegistrationBuilder /// Service type to provide a composite for. + /// The composite registration for continued configuration. public static IRegistrationBuilder RegisterComposite( this ContainerBuilder builder, Func, IEnumerable, TService> compositeDelegate) @@ -129,6 +132,7 @@ public static IRegistrationBuilder /// Service type to provide a composite for. + /// The composite registration for continued configuration. public static IRegistrationBuilder RegisterComposite( this ContainerBuilder builder, Func, TService> compositeDelegate) @@ -154,6 +158,7 @@ public static IRegistrationBuilder /// Service type to provide a composite for. + /// The composite registration for continued configuration. public static IRegistrationBuilder RegisterGenericComposite( this ContainerBuilder builder, [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] Type compositeType, diff --git a/src/Autofac/RegistrationExtensions.Decorators.cs b/src/Autofac/RegistrationExtensions.Decorators.cs index 872646b54..d553af933 100644 --- a/src/Autofac/RegistrationExtensions.Decorators.cs +++ b/src/Autofac/RegistrationExtensions.Decorators.cs @@ -27,6 +27,7 @@ public static partial class RegistrationExtensions /// Service key or name given to the decorated components. /// The type of the decorator. Must be an open generic type, and accept a parameter /// of type , which will be set to the instance being decorated. + /// The decorator registration for continued configuration. public static IRegistrationBuilder RegisterGenericDecorator( this ContainerBuilder builder, @@ -64,6 +65,7 @@ public static IRegistrationBuilder, given the context and parameters. /// Service key or name associated with the components being decorated. /// Service key or name given to the decorated components. + /// The decorator registration for continued configuration. public static IRegistrationBuilder RegisterDecorator( this ContainerBuilder builder, @@ -96,6 +98,7 @@ public static IRegistrationBuilder, given the context. /// Service key or name associated with the components being decorated. /// Service key or name given to the decorated components. + /// The decorator registration for continued configuration. public static IRegistrationBuilder RegisterDecorator( this ContainerBuilder builder, @@ -128,6 +131,7 @@ public static IRegistrationBuilder. /// Service key or name associated with the components being decorated. /// Service key or name given to the decorated components. + /// The decorator registration for continued configuration. public static IRegistrationBuilder RegisterDecorator( this ContainerBuilder builder, @@ -157,8 +161,7 @@ public static IRegistrationBuilder, which will be set to the instance being decorated. /// Service type being decorated. /// Container builder. - /// A function that when provided with an - /// instance determines if the decorator should be applied. + /// A function that when provided with an instance determines if the decorator should be applied. public static void RegisterDecorator<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] TDecorator, TService>(this ContainerBuilder builder, Func? condition = null) where TDecorator : notnull, TService { @@ -188,8 +191,7 @@ public static IRegistrationBuilderService type of the decorator. Must accept a parameter /// of type , which will be set to the instance being decorated. /// Service type being decorated. - /// A function that when provided with an - /// instance determines if the decorator should be applied. + /// A function that when provided with an instance determines if the decorator should be applied. public static void RegisterDecorator( this ContainerBuilder builder, [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] Type decoratorType, @@ -233,8 +235,7 @@ public static void RegisterDecorator( /// Container builder. /// Function decorating a component instance that provides /// , given the context, parameters and service to decorate. - /// A function that when provided with an - /// instance determines if the decorator should be applied. + /// A function that when provided with an instance determines if the decorator should be applied. public static void RegisterDecorator( this ContainerBuilder builder, Func, TService, TService> decorator, @@ -279,8 +280,7 @@ public static void RegisterDecorator( /// The type of the decorator. Must be an open generic type, and accept a parameter /// of type , which will be set to the instance being decorated. /// Service type being decorated. Must be an open generic type. - /// A function that when provided with an - /// instance determines if the decorator should be applied. + /// A function that when provided with an instance determines if the decorator should be applied. public static void RegisterGenericDecorator( this ContainerBuilder builder, [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] Type decoratorType, diff --git a/src/Autofac/TypeExtensions.cs b/src/Autofac/TypeExtensions.cs index a123b5fa5..1b9ac1b3e 100644 --- a/src/Autofac/TypeExtensions.cs +++ b/src/Autofac/TypeExtensions.cs @@ -65,6 +65,7 @@ public static bool IsInNamespaceOf(this Type @this) /// /// The type to test. /// The open generic against which the type should be tested. + /// if the provided type is a closed version of the provided open generic; otherwise, . public static bool IsClosedTypeOf(this Type @this, Type openGeneric) { if (@this == null) @@ -90,8 +91,7 @@ public static bool IsClosedTypeOf(this Type @this, Type openGeneric) /// /// The type to test assignability to. /// The type to test. - /// True if this type is assignable to references of type - /// ; otherwise, False. + /// if this type is assignable to references of type ; otherwise, . public static bool IsAssignableTo(this Type @this) { if (@this == null) diff --git a/src/Autofac/Util/Cache/TypeAssemblyReferenceProvider.cs b/src/Autofac/Util/Cache/TypeAssemblyReferenceProvider.cs index c85e30902..fec0cac8c 100644 --- a/src/Autofac/Util/Cache/TypeAssemblyReferenceProvider.cs +++ b/src/Autofac/Util/Cache/TypeAssemblyReferenceProvider.cs @@ -36,6 +36,9 @@ public static IEnumerable GetAllReferencedAssemblies(MemberInfo member /// /// The holding set is cleared each time this method is called. /// + /// + /// The set of assemblies added to the provided . + /// public static IEnumerable GetAllReferencedAssemblies(MemberInfo memberInfo, HashSet holdingSet) { holdingSet.Clear(); diff --git a/src/Autofac/Util/Disposable.cs b/src/Autofac/Util/Disposable.cs index 3c033cbb1..55216c237 100644 --- a/src/Autofac/Util/Disposable.cs +++ b/src/Autofac/Util/Disposable.cs @@ -71,7 +71,8 @@ public ValueTask DisposeAsync() /// /// Releases unmanaged and - optionally - managed resources, asynchronously. /// - /// true to release both managed and unmanaged resources; false to release only unmanaged resources. + /// to release both managed and unmanaged resources; to release only unmanaged resources. + /// A task to await disposal. protected virtual ValueTask DisposeAsync(bool disposing) { // Default implementation does a synchronous dispose. diff --git a/src/Autofac/Util/Enforce.cs b/src/Autofac/Util/Enforce.cs index 23422852f..56e2a586b 100644 --- a/src/Autofac/Util/Enforce.cs +++ b/src/Autofac/Util/Enforce.cs @@ -18,8 +18,8 @@ internal static class Enforce /// /// The value. /// The parameter name. - [SuppressMessage("ReSharper", "PossibleMultipleEnumeration")] - public static IEnumerable ArgumentElementNotNull(IEnumerable value, string name) + /// The if there are no null elements. Throws an exception if the is null or contains null elements. + public static IEnumerable ArgumentElementNotNull(IEnumerable? value, string name) where T : class { if (value == null) From 3b59b7a349f4a895bfe6cb453cd0843011563963 Mon Sep 17 00:00:00 2001 From: Travis Illig Date: Thu, 18 Sep 2025 09:44:48 -0700 Subject: [PATCH 02/15] Use for true/false. --- src/Autofac/Core/Container.cs | 2 +- src/Autofac/Core/Disposer.cs | 2 +- src/Autofac/Core/ISharingLifetimeScope.cs | 4 ++-- src/Autofac/Core/Lifetime/LifetimeScope.cs | 2 +- src/Autofac/Features/OwnedInstances/Owned.cs | 2 +- src/Autofac/Util/Disposable.cs | 2 +- 6 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/Autofac/Core/Container.cs b/src/Autofac/Core/Container.cs index b1729503c..c5d0edee1 100644 --- a/src/Autofac/Core/Container.cs +++ b/src/Autofac/Core/Container.cs @@ -148,7 +148,7 @@ public object ResolveComponent(in ResolveRequest request) /// /// Releases unmanaged and - optionally - managed resources. /// - /// true to release both managed and unmanaged resources; false to release only unmanaged resources. + /// to release both managed and unmanaged resources; to release only unmanaged resources. protected override void Dispose(bool disposing) { if (disposing) diff --git a/src/Autofac/Core/Disposer.cs b/src/Autofac/Core/Disposer.cs index a093b49e5..0ca084000 100644 --- a/src/Autofac/Core/Disposer.cs +++ b/src/Autofac/Core/Disposer.cs @@ -24,7 +24,7 @@ internal class Disposer : Disposable, IDisposer /// /// Releases unmanaged and - optionally - managed resources. /// - /// true to release both managed and unmanaged resources; false to release only unmanaged resources. + /// to release both managed and unmanaged resources; to release only unmanaged resources. protected override void Dispose(bool disposing) { if (disposing) diff --git a/src/Autofac/Core/ISharingLifetimeScope.cs b/src/Autofac/Core/ISharingLifetimeScope.cs index becbb672d..6414fc575 100644 --- a/src/Autofac/Core/ISharingLifetimeScope.cs +++ b/src/Autofac/Core/ISharingLifetimeScope.cs @@ -23,7 +23,7 @@ public interface ISharingLifetimeScope : ILifetimeScope /// /// Key to look up. /// The instance that has the specified key. - /// true if the key was found; otherwise, false. + /// if the key was found; otherwise, . bool TryGetSharedInstance(Guid id, [NotNullWhen(true)] out object? value); /// @@ -36,7 +36,7 @@ public interface ISharingLifetimeScope : ILifetimeScope /// or is otherwise "namespaced" by it. /// /// The instance that has the specified keys. - /// true if the key was found; otherwise, false. + /// if the key was found; otherwise, . bool TryGetSharedInstance(Guid primaryId, Guid? qualifyingId, [NotNullWhen(true)] out object? value); /// diff --git a/src/Autofac/Core/Lifetime/LifetimeScope.cs b/src/Autofac/Core/Lifetime/LifetimeScope.cs index 61364fbd2..303690daf 100644 --- a/src/Autofac/Core/Lifetime/LifetimeScope.cs +++ b/src/Autofac/Core/Lifetime/LifetimeScope.cs @@ -442,7 +442,7 @@ public bool TryGetSharedInstance(Guid primaryId, Guid? qualifyingId, [NotNullWhe /// /// Releases unmanaged and - optionally - managed resources. /// - /// true to release both managed and unmanaged resources; false to release only unmanaged resources. + /// to release both managed and unmanaged resources; to release only unmanaged resources. protected override void Dispose(bool disposing) { if (disposing) diff --git a/src/Autofac/Features/OwnedInstances/Owned.cs b/src/Autofac/Features/OwnedInstances/Owned.cs index 040453daa..044d63adc 100644 --- a/src/Autofac/Features/OwnedInstances/Owned.cs +++ b/src/Autofac/Features/OwnedInstances/Owned.cs @@ -85,7 +85,7 @@ public Owned(T value, IDisposable lifetime) /// /// Releases unmanaged and - optionally - managed resources. /// - /// true to release both managed and unmanaged resources; false to release only unmanaged resources. + /// to release both managed and unmanaged resources; to release only unmanaged resources. protected override void Dispose(bool disposing) { if (disposing) diff --git a/src/Autofac/Util/Disposable.cs b/src/Autofac/Util/Disposable.cs index 55216c237..8d192aaea 100644 --- a/src/Autofac/Util/Disposable.cs +++ b/src/Autofac/Util/Disposable.cs @@ -30,7 +30,7 @@ public void Dispose() /// /// Releases unmanaged and - optionally - managed resources. /// - /// true to release both managed and unmanaged resources; false to release only unmanaged resources. + /// to release both managed and unmanaged resources; to release only unmanaged resources. protected virtual void Dispose(bool disposing) { } From eea2911321e5ed666c7c85ed68df3a643faff6ab Mon Sep 17 00:00:00 2001 From: Travis Illig Date: Thu, 18 Sep 2025 10:04:46 -0700 Subject: [PATCH 03/15] Enable generic type parameter documentation and fix missing docs. --- build/Source.ruleset | 4 +--- src/Autofac/Builder/IRegistrationBuilder.cs | 3 +-- src/Autofac/Builder/RegistrationBuilder.cs | 7 ++++++- src/Autofac/Core/ActivatedEventArgs.cs | 3 ++- src/Autofac/Core/ActivatingEventArgs.cs | 1 + src/Autofac/Core/IActivatedEventArgs.cs | 3 ++- src/Autofac/Core/IActivatingEventArgs.cs | 1 + .../Features/GeneratedFactories/FactoryGenerator.cs | 1 + .../GeneratedFactoryRegistrationExtensions.cs | 1 + src/Autofac/Features/Scanning/BaseScanningActivatorData.cs | 2 ++ src/Autofac/RegistrationExtensions.cs | 3 +++ src/Autofac/TypeExtensions.cs | 1 + src/Autofac/Util/AsyncReleaseAction.cs | 1 + src/Autofac/Util/Enforce.cs | 1 + src/Autofac/Util/FallbackDictionary.cs | 2 ++ src/Autofac/Util/ReleaseAction.cs | 1 + 16 files changed, 27 insertions(+), 8 deletions(-) diff --git a/build/Source.ruleset b/build/Source.ruleset index 6d30f8bb3..ac1fcb66d 100644 --- a/build/Source.ruleset +++ b/build/Source.ruleset @@ -32,7 +32,7 @@ - + @@ -46,8 +46,6 @@ - - diff --git a/src/Autofac/Builder/IRegistrationBuilder.cs b/src/Autofac/Builder/IRegistrationBuilder.cs index 2564c3f02..0cc0c1ba9 100644 --- a/src/Autofac/Builder/IRegistrationBuilder.cs +++ b/src/Autofac/Builder/IRegistrationBuilder.cs @@ -10,8 +10,7 @@ namespace Autofac.Builder; /// /// Data structure used to construct registrations. /// -/// The most specific type to which instances of the registration -/// can be cast. +/// The most specific type to which instances of the registration can be cast. /// Activator builder type. /// Registration style type. public interface IRegistrationBuilder diff --git a/src/Autofac/Builder/RegistrationBuilder.cs b/src/Autofac/Builder/RegistrationBuilder.cs index b3d3177c4..9b441aa20 100644 --- a/src/Autofac/Builder/RegistrationBuilder.cs +++ b/src/Autofac/Builder/RegistrationBuilder.cs @@ -101,6 +101,9 @@ public static IRegistrationBuilder from a . /// There is no need to call this method when registering components through a . /// + /// The most specific type to which instances of the registration can be cast. + /// Activator builder type. + /// Registration style for individual components. /// /// When called on the result of one of the methods, /// the returned registration will be different from the one the builder itself registers @@ -253,7 +256,9 @@ public static IComponentRegistration CreateRegistration( /// Register a component in the component registry. This helper method is necessary /// in order to execute OnRegistered hooks and respect PreserveDefaults. /// - /// Hoping to refactor this out. + /// The most specific type to which instances of the registration can be cast. + /// Activator builder type. + /// Registration style for individual components. /// Component registry to make registration in. /// Registration builder with data for new registration. public static void RegisterSingleComponent( diff --git a/src/Autofac/Core/ActivatedEventArgs.cs b/src/Autofac/Core/ActivatedEventArgs.cs index dde805e8e..65b365ff3 100644 --- a/src/Autofac/Core/ActivatedEventArgs.cs +++ b/src/Autofac/Core/ActivatedEventArgs.cs @@ -6,6 +6,7 @@ namespace Autofac.Core; /// /// Fired when the activation process for a new instance is complete. /// +/// The type of instance being used to satisfy the request. public class ActivatedEventArgs : EventArgs, IActivatedEventArgs { /// @@ -46,7 +47,7 @@ public ActivatedEventArgs( public IComponentRegistration Component { get; } /// - /// Gets the paramters provided when resolved. + /// Gets the parameters provided when resolved. /// public IEnumerable Parameters { get; } diff --git a/src/Autofac/Core/ActivatingEventArgs.cs b/src/Autofac/Core/ActivatingEventArgs.cs index 55e1d24ee..b73aee76c 100644 --- a/src/Autofac/Core/ActivatingEventArgs.cs +++ b/src/Autofac/Core/ActivatingEventArgs.cs @@ -7,6 +7,7 @@ namespace Autofac.Core; /// Fired after the construction of an instance but before that instance /// is shared with any other or any members are invoked on it. /// +/// The type of instance being used to satisfy the request. public class ActivatingEventArgs : EventArgs, IActivatingEventArgs where T : notnull { diff --git a/src/Autofac/Core/IActivatedEventArgs.cs b/src/Autofac/Core/IActivatedEventArgs.cs index f07f28db9..c5dd00852 100644 --- a/src/Autofac/Core/IActivatedEventArgs.cs +++ b/src/Autofac/Core/IActivatedEventArgs.cs @@ -6,6 +6,7 @@ namespace Autofac.Core; /// /// Fired when the activation process for a new instance is complete. /// +/// The type of instance being used to satisfy the request. [SuppressMessage("Microsoft.Naming", "CA1711:IdentifiersShouldNotHaveIncorrectSuffix")] public interface IActivatedEventArgs { @@ -25,7 +26,7 @@ public interface IActivatedEventArgs IComponentRegistration Component { get; } /// - /// Gets the paramters provided when resolved. + /// Gets the parameters provided when resolved. /// IEnumerable Parameters { get; } diff --git a/src/Autofac/Core/IActivatingEventArgs.cs b/src/Autofac/Core/IActivatingEventArgs.cs index 44a5bf0e1..40323191a 100644 --- a/src/Autofac/Core/IActivatingEventArgs.cs +++ b/src/Autofac/Core/IActivatingEventArgs.cs @@ -7,6 +7,7 @@ namespace Autofac.Core; /// Fired after the construction of an instance but before that instance /// is shared with any other or any members are invoked on it. /// +/// The type of instance being used to satisfy the request. [SuppressMessage("Microsoft.Naming", "CA1711:IdentifiersShouldNotHaveIncorrectSuffix")] public interface IActivatingEventArgs { diff --git a/src/Autofac/Features/GeneratedFactories/FactoryGenerator.cs b/src/Autofac/Features/GeneratedFactories/FactoryGenerator.cs index bc0213ff9..1177b796c 100644 --- a/src/Autofac/Features/GeneratedFactories/FactoryGenerator.cs +++ b/src/Autofac/Features/GeneratedFactories/FactoryGenerator.cs @@ -209,6 +209,7 @@ public Delegate GenerateFactory(IComponentContext context, IEnumerable /// Generates a factory delegate that closes over the provided context. /// + /// The type of the delegate to generate. /// The context in which the factory will be used. /// Parameters provided to the resolve call for the factory itself. /// A factory delegate that will work within the context. diff --git a/src/Autofac/Features/GeneratedFactories/GeneratedFactoryRegistrationExtensions.cs b/src/Autofac/Features/GeneratedFactories/GeneratedFactoryRegistrationExtensions.cs index 8944ec3eb..68f586e0c 100644 --- a/src/Autofac/Features/GeneratedFactories/GeneratedFactoryRegistrationExtensions.cs +++ b/src/Autofac/Features/GeneratedFactories/GeneratedFactoryRegistrationExtensions.cs @@ -16,6 +16,7 @@ internal static class GeneratedFactoryRegistrationExtensions /// /// Registers a factory delegate. /// + /// The most specific type to which instances of the registration can be cast. /// Container builder. /// Factory type to generate. /// The service that the delegate will return instances of. diff --git a/src/Autofac/Features/Scanning/BaseScanningActivatorData.cs b/src/Autofac/Features/Scanning/BaseScanningActivatorData.cs index 24f653cdc..48a40e38b 100644 --- a/src/Autofac/Features/Scanning/BaseScanningActivatorData.cs +++ b/src/Autofac/Features/Scanning/BaseScanningActivatorData.cs @@ -9,6 +9,8 @@ namespace Autofac.Features.Scanning; /// /// Base activation data for types located by scanning assemblies. /// +/// Activator data type. +/// Registration style type. public abstract class BaseScanningActivatorData : ReflectionActivatorData where TActivatorData : ReflectionActivatorData { diff --git a/src/Autofac/RegistrationExtensions.cs b/src/Autofac/RegistrationExtensions.cs index 55b7e579f..7b25d06a3 100644 --- a/src/Autofac/RegistrationExtensions.cs +++ b/src/Autofac/RegistrationExtensions.cs @@ -345,6 +345,9 @@ public static IRegistrationBuilder /// Configure the component so that any properties whose types are registered in the /// container will be wired to instances of the appropriate service. /// + /// The most specific type to which instances of the registration can be cast. + /// Activator builder type. + /// Registration style type. /// Registration to auto-wire properties. /// Set wiring options such as circular dependency wiring support. /// A registration builder allowing further configuration of the component. diff --git a/src/Autofac/TypeExtensions.cs b/src/Autofac/TypeExtensions.cs index 1b9ac1b3e..fe6b54f23 100644 --- a/src/Autofac/TypeExtensions.cs +++ b/src/Autofac/TypeExtensions.cs @@ -45,6 +45,7 @@ public static bool IsInNamespace(this Type @this, string @namespace) /// Returns true if this type is in the same namespace as /// or one of its sub-namespaces. /// + /// The type whose namespace is used for comparison. /// The type to test. /// True if this type is in the same namespace as /// or one of its sub-namespaces; otherwise, false. diff --git a/src/Autofac/Util/AsyncReleaseAction.cs b/src/Autofac/Util/AsyncReleaseAction.cs index 9dc7f013f..0b2d0d57b 100644 --- a/src/Autofac/Util/AsyncReleaseAction.cs +++ b/src/Autofac/Util/AsyncReleaseAction.cs @@ -6,6 +6,7 @@ namespace Autofac.Util; /// /// Adapts an async action to the interface. /// +/// The most specific type to which instances of the registration can be cast. internal class AsyncReleaseAction : Disposable { private readonly Func _action; diff --git a/src/Autofac/Util/Enforce.cs b/src/Autofac/Util/Enforce.cs index 56e2a586b..69095b7cd 100644 --- a/src/Autofac/Util/Enforce.cs +++ b/src/Autofac/Util/Enforce.cs @@ -16,6 +16,7 @@ internal static class Enforce /// value if valid so that it can be used inline in /// base initializer syntax. /// + /// The type of elements in the sequence. /// The value. /// The parameter name. /// The if there are no null elements. Throws an exception if the is null or contains null elements. diff --git a/src/Autofac/Util/FallbackDictionary.cs b/src/Autofac/Util/FallbackDictionary.cs index 4b60ed6d4..6cc47ff67 100644 --- a/src/Autofac/Util/FallbackDictionary.cs +++ b/src/Autofac/Util/FallbackDictionary.cs @@ -9,6 +9,8 @@ namespace Autofac.Util; /// /// Dictionary used to allow local property get/set and fall back to parent values. /// +/// The type of the keys in the dictionary. +/// The type of the values in the dictionary. internal class FallbackDictionary : IDictionary where TKey : notnull { diff --git a/src/Autofac/Util/ReleaseAction.cs b/src/Autofac/Util/ReleaseAction.cs index 9d0dc6c5d..17714a747 100644 --- a/src/Autofac/Util/ReleaseAction.cs +++ b/src/Autofac/Util/ReleaseAction.cs @@ -6,6 +6,7 @@ namespace Autofac.Util; /// /// Adapts an action to the interface. /// +/// The most specific type to which instances of the registration can be cast. internal class ReleaseAction : Disposable { private readonly Action _action; From 8c7612e40bbe01ee7869d42350705120c745babe Mon Sep 17 00:00:00 2001 From: Travis Illig Date: Thu, 18 Sep 2025 10:17:57 -0700 Subject: [PATCH 04/15] Enable suppression justification rule. --- build/Source.ruleset | 4 ---- src/Autofac/Builder/IHideObjectMembers.cs | 2 +- src/Autofac/Core/IActivatedEventArgs.cs | 2 +- src/Autofac/Core/IActivatingEventArgs.cs | 2 +- src/Autofac/Core/Parameter.cs | 1 - src/Autofac/RegistrationExtensions.Adapter.cs | 2 +- src/Autofac/RegistrationExtensions.AssemblyScanning.cs | 2 +- src/Autofac/RegistrationExtensions.Composite.cs | 2 +- src/Autofac/RegistrationExtensions.Conditional.cs | 2 +- src/Autofac/RegistrationExtensions.Decorators.cs | 2 +- src/Autofac/RegistrationExtensions.EventHandler.cs | 2 +- src/Autofac/RegistrationExtensions.Generics.cs | 2 +- src/Autofac/RegistrationExtensions.Keyed.cs | 2 +- src/Autofac/RegistrationExtensions.Named.cs | 2 +- .../RegistrationExtensions.OpenGenericAssemblyScanning.cs | 2 +- src/Autofac/RegistrationExtensions.cs | 2 +- src/Autofac/ResolutionExtensions.cs | 5 ----- src/Autofac/TypedParameter.cs | 2 +- 18 files changed, 15 insertions(+), 25 deletions(-) diff --git a/build/Source.ruleset b/build/Source.ruleset index ac1fcb66d..00ee46790 100644 --- a/build/Source.ruleset +++ b/build/Source.ruleset @@ -26,8 +26,6 @@ - - @@ -42,8 +40,6 @@ - - diff --git a/src/Autofac/Builder/IHideObjectMembers.cs b/src/Autofac/Builder/IHideObjectMembers.cs index a0bb0b668..4e6893cea 100644 --- a/src/Autofac/Builder/IHideObjectMembers.cs +++ b/src/Autofac/Builder/IHideObjectMembers.cs @@ -18,7 +18,7 @@ public interface IHideObjectMembers /// Standard System.Object member. /// /// Standard result. - [SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate")] + [SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate", Justification = "Override for standard method to add attributes.")] [EditorBrowsable(EditorBrowsableState.Never)] Type GetType(); diff --git a/src/Autofac/Core/IActivatedEventArgs.cs b/src/Autofac/Core/IActivatedEventArgs.cs index c5dd00852..5dd0f310d 100644 --- a/src/Autofac/Core/IActivatedEventArgs.cs +++ b/src/Autofac/Core/IActivatedEventArgs.cs @@ -7,7 +7,7 @@ namespace Autofac.Core; /// Fired when the activation process for a new instance is complete. /// /// The type of instance being used to satisfy the request. -[SuppressMessage("Microsoft.Naming", "CA1711:IdentifiersShouldNotHaveIncorrectSuffix")] +[SuppressMessage("Microsoft.Naming", "CA1711:IdentifiersShouldNotHaveIncorrectSuffix", Justification = "Event args naming here occurred before the rule was created.")] public interface IActivatedEventArgs { /// diff --git a/src/Autofac/Core/IActivatingEventArgs.cs b/src/Autofac/Core/IActivatingEventArgs.cs index 40323191a..e8a594a58 100644 --- a/src/Autofac/Core/IActivatingEventArgs.cs +++ b/src/Autofac/Core/IActivatingEventArgs.cs @@ -8,7 +8,7 @@ namespace Autofac.Core; /// is shared with any other or any members are invoked on it. /// /// The type of instance being used to satisfy the request. -[SuppressMessage("Microsoft.Naming", "CA1711:IdentifiersShouldNotHaveIncorrectSuffix")] +[SuppressMessage("Microsoft.Naming", "CA1711:IdentifiersShouldNotHaveIncorrectSuffix", Justification = "Event args naming here occurred before the rule was created.")] public interface IActivatingEventArgs { /// diff --git a/src/Autofac/Core/Parameter.cs b/src/Autofac/Core/Parameter.cs index 95e7cf6ce..c46ba01d6 100644 --- a/src/Autofac/Core/Parameter.cs +++ b/src/Autofac/Core/Parameter.cs @@ -23,6 +23,5 @@ public abstract class Parameter /// be set to a function that will lazily retrieve the parameter value. If the result is false, /// will be set to null. /// True if a value can be supplied; otherwise, false. - [SuppressMessage("Microsoft.Design", "CA1021:AvoidOutParameters", MessageId = "2#")] public abstract bool CanSupplyValue(ParameterInfo pi, IComponentContext context, [NotNullWhen(returnValue: true)] out Func? valueProvider); } diff --git a/src/Autofac/RegistrationExtensions.Adapter.cs b/src/Autofac/RegistrationExtensions.Adapter.cs index 35b2f9cd0..408fb748b 100644 --- a/src/Autofac/RegistrationExtensions.Adapter.cs +++ b/src/Autofac/RegistrationExtensions.Adapter.cs @@ -10,7 +10,7 @@ namespace Autofac; /// /// Adds registration syntax to the type. /// -[SuppressMessage("Microsoft.Maintainability", "CA1506:AvoidExcessiveClassCoupling")] +[SuppressMessage("Microsoft.Maintainability", "CA1506:AvoidExcessiveClassCoupling", Justification = "RegistrationBuilder is where all registration syntax lives.")] public static partial class RegistrationExtensions { /// diff --git a/src/Autofac/RegistrationExtensions.AssemblyScanning.cs b/src/Autofac/RegistrationExtensions.AssemblyScanning.cs index c2eec6b03..9324e6138 100644 --- a/src/Autofac/RegistrationExtensions.AssemblyScanning.cs +++ b/src/Autofac/RegistrationExtensions.AssemblyScanning.cs @@ -12,7 +12,7 @@ namespace Autofac; /// /// Adds registration syntax to the type. /// -[SuppressMessage("Microsoft.Maintainability", "CA1506:AvoidExcessiveClassCoupling")] +[SuppressMessage("Microsoft.Maintainability", "CA1506:AvoidExcessiveClassCoupling", Justification = "RegistrationBuilder is where all registration syntax lives.")] public static partial class RegistrationExtensions { private const string AssemblyScanningWarning = "Assembly scanning is unlikely to be compatible with member-level trimming; the linker will not be able to determine which types to preserve."; diff --git a/src/Autofac/RegistrationExtensions.Composite.cs b/src/Autofac/RegistrationExtensions.Composite.cs index cd06df0d4..75a2cf316 100644 --- a/src/Autofac/RegistrationExtensions.Composite.cs +++ b/src/Autofac/RegistrationExtensions.Composite.cs @@ -11,7 +11,7 @@ namespace Autofac; /// /// Adds registration syntax to the type. /// -[SuppressMessage("Microsoft.Maintainability", "CA1506:AvoidExcessiveClassCoupling")] +[SuppressMessage("Microsoft.Maintainability", "CA1506:AvoidExcessiveClassCoupling", Justification = "RegistrationBuilder is where all registration syntax lives.")] public static partial class RegistrationExtensions { /// diff --git a/src/Autofac/RegistrationExtensions.Conditional.cs b/src/Autofac/RegistrationExtensions.Conditional.cs index 57f9c549c..2c81c04ba 100644 --- a/src/Autofac/RegistrationExtensions.Conditional.cs +++ b/src/Autofac/RegistrationExtensions.Conditional.cs @@ -10,7 +10,7 @@ namespace Autofac; /// /// Adds registration syntax to the type. /// -[SuppressMessage("Microsoft.Maintainability", "CA1506:AvoidExcessiveClassCoupling")] +[SuppressMessage("Microsoft.Maintainability", "CA1506:AvoidExcessiveClassCoupling", Justification = "RegistrationBuilder is where all registration syntax lives.")] public static partial class RegistrationExtensions { /// diff --git a/src/Autofac/RegistrationExtensions.Decorators.cs b/src/Autofac/RegistrationExtensions.Decorators.cs index d553af933..6e3e9d0c5 100644 --- a/src/Autofac/RegistrationExtensions.Decorators.cs +++ b/src/Autofac/RegistrationExtensions.Decorators.cs @@ -14,7 +14,7 @@ namespace Autofac; /// /// Adds registration syntax to the type. /// -[SuppressMessage("Microsoft.Maintainability", "CA1506:AvoidExcessiveClassCoupling")] +[SuppressMessage("Microsoft.Maintainability", "CA1506:AvoidExcessiveClassCoupling", Justification = "RegistrationBuilder is where all registration syntax lives.")] public static partial class RegistrationExtensions { /// diff --git a/src/Autofac/RegistrationExtensions.EventHandler.cs b/src/Autofac/RegistrationExtensions.EventHandler.cs index 5c87070b7..5d01efd23 100644 --- a/src/Autofac/RegistrationExtensions.EventHandler.cs +++ b/src/Autofac/RegistrationExtensions.EventHandler.cs @@ -13,7 +13,7 @@ namespace Autofac; /// /// Adds registration syntax to the type. /// -[SuppressMessage("Microsoft.Maintainability", "CA1506:AvoidExcessiveClassCoupling")] +[SuppressMessage("Microsoft.Maintainability", "CA1506:AvoidExcessiveClassCoupling", Justification = "RegistrationBuilder is where all registration syntax lives.")] public static partial class RegistrationExtensions { /// diff --git a/src/Autofac/RegistrationExtensions.Generics.cs b/src/Autofac/RegistrationExtensions.Generics.cs index fd85f13c6..960472c9d 100644 --- a/src/Autofac/RegistrationExtensions.Generics.cs +++ b/src/Autofac/RegistrationExtensions.Generics.cs @@ -10,7 +10,7 @@ namespace Autofac; /// /// Adds registration syntax to the type. /// -[SuppressMessage("Microsoft.Maintainability", "CA1506:AvoidExcessiveClassCoupling")] +[SuppressMessage("Microsoft.Maintainability", "CA1506:AvoidExcessiveClassCoupling", Justification = "RegistrationBuilder is where all registration syntax lives.")] public static partial class RegistrationExtensions { /// diff --git a/src/Autofac/RegistrationExtensions.Keyed.cs b/src/Autofac/RegistrationExtensions.Keyed.cs index c724c9fd6..360fbd728 100644 --- a/src/Autofac/RegistrationExtensions.Keyed.cs +++ b/src/Autofac/RegistrationExtensions.Keyed.cs @@ -10,7 +10,7 @@ namespace Autofac; /// /// Adds registration syntax to the type. /// -[SuppressMessage("Microsoft.Maintainability", "CA1506:AvoidExcessiveClassCoupling")] +[SuppressMessage("Microsoft.Maintainability", "CA1506:AvoidExcessiveClassCoupling", Justification = "RegistrationBuilder is where all registration syntax lives.")] public static partial class RegistrationExtensions { /// diff --git a/src/Autofac/RegistrationExtensions.Named.cs b/src/Autofac/RegistrationExtensions.Named.cs index af95823b4..b16275570 100644 --- a/src/Autofac/RegistrationExtensions.Named.cs +++ b/src/Autofac/RegistrationExtensions.Named.cs @@ -10,7 +10,7 @@ namespace Autofac; /// /// Adds registration syntax to the type. /// -[SuppressMessage("Microsoft.Maintainability", "CA1506:AvoidExcessiveClassCoupling")] +[SuppressMessage("Microsoft.Maintainability", "CA1506:AvoidExcessiveClassCoupling", Justification = "RegistrationBuilder is where all registration syntax lives.")] public static partial class RegistrationExtensions { /// diff --git a/src/Autofac/RegistrationExtensions.OpenGenericAssemblyScanning.cs b/src/Autofac/RegistrationExtensions.OpenGenericAssemblyScanning.cs index 30be779f4..ef42cedd0 100644 --- a/src/Autofac/RegistrationExtensions.OpenGenericAssemblyScanning.cs +++ b/src/Autofac/RegistrationExtensions.OpenGenericAssemblyScanning.cs @@ -13,7 +13,7 @@ namespace Autofac; /// /// Adds registration syntax to the type. /// -[SuppressMessage("Microsoft.Maintainability", "CA1506:AvoidExcessiveClassCoupling")] +[SuppressMessage("Microsoft.Maintainability", "CA1506:AvoidExcessiveClassCoupling", Justification = "RegistrationBuilder is where all registration syntax lives.")] public static partial class RegistrationExtensions { /// diff --git a/src/Autofac/RegistrationExtensions.cs b/src/Autofac/RegistrationExtensions.cs index 7b25d06a3..7cf3925fc 100644 --- a/src/Autofac/RegistrationExtensions.cs +++ b/src/Autofac/RegistrationExtensions.cs @@ -19,7 +19,7 @@ namespace Autofac; /// /// Adds registration syntax to the type. /// -[SuppressMessage("Microsoft.Maintainability", "CA1506:AvoidExcessiveClassCoupling")] +[SuppressMessage("Microsoft.Maintainability", "CA1506:AvoidExcessiveClassCoupling", Justification = "RegistrationBuilder is where all registration syntax lives.")] public static partial class RegistrationExtensions { /// diff --git a/src/Autofac/ResolutionExtensions.cs b/src/Autofac/ResolutionExtensions.cs index 9d9cf0caf..bf76a3323 100644 --- a/src/Autofac/ResolutionExtensions.cs +++ b/src/Autofac/ResolutionExtensions.cs @@ -924,7 +924,6 @@ public static bool TryResolve(this IComponentContext context, [NotNullWhen(re /// True if a component providing the service is available. /// /// - [SuppressMessage("Microsoft.Design", "CA1007:UseGenericsWhereAppropriate")] public static bool TryResolve(this IComponentContext context, Type serviceType, [NotNullWhen(returnValue: true)] out object? instance) { return context.TryResolveService(new TypedService(serviceType), ResolveRequest.NoParameters, out instance); @@ -969,7 +968,6 @@ public static bool TryResolveKeyed(this IComponentContext context, object ser /// True if a component providing the service is available. /// /// - [SuppressMessage("Microsoft.Design", "CA1007:UseGenericsWhereAppropriate")] public static bool TryResolveKeyed(this IComponentContext context, object serviceKey, Type serviceType, [NotNullWhen(returnValue: true)] out object? instance) { return context.TryResolveService(new KeyedService(serviceKey, serviceType), ResolveRequest.NoParameters, out instance); @@ -1014,7 +1012,6 @@ public static bool TryResolveNamed(this IComponentContext context, string ser /// True if a component providing the service is available. /// /// - [SuppressMessage("Microsoft.Design", "CA1007:UseGenericsWhereAppropriate")] public static bool TryResolveNamed(this IComponentContext context, string serviceName, Type serviceType, [NotNullWhen(returnValue: true)] out object? instance) { return context.TryResolveService(new KeyedService(serviceName, serviceType), ResolveRequest.NoParameters, out instance); @@ -1030,7 +1027,6 @@ public static bool TryResolveNamed(this IComponentContext context, string servic /// True if a component providing the service is available. /// /// - [SuppressMessage("Microsoft.Design", "CA1007:UseGenericsWhereAppropriate")] public static bool TryResolveService(this IComponentContext context, Service service, [NotNullWhen(returnValue: true)] out object? instance) { return context.TryResolveService(service, ResolveRequest.NoParameters, out instance); @@ -1050,7 +1046,6 @@ public static bool TryResolveService(this IComponentContext context, Service ser /// /// Thrown if is . /// - [SuppressMessage("Microsoft.Design", "CA1007:UseGenericsWhereAppropriate")] public static bool TryResolveService(this IComponentContext context, Service service, IEnumerable parameters, [NotNullWhen(returnValue: true)] out object? instance) { if (context == null) diff --git a/src/Autofac/TypedParameter.cs b/src/Autofac/TypedParameter.cs index edc12a3df..4a4376240 100644 --- a/src/Autofac/TypedParameter.cs +++ b/src/Autofac/TypedParameter.cs @@ -38,7 +38,7 @@ public class TypedParameter : ConstantParameter /// /// Gets the type against which targets are matched. /// - [SuppressMessage("Microsoft.Naming", "CA1721:PropertyNamesShouldNotMatchGetMethods")] + [SuppressMessage("Microsoft.Naming", "CA1721:PropertyNamesShouldNotMatchGetMethods", Justification = "Property serves a different purpose than the default get method.")] public Type Type { get; private set; } /// From 9e2e609e8e51aa877ebdcec69a4bab23133f64d9 Mon Sep 17 00:00:00 2001 From: Travis Illig Date: Thu, 18 Sep 2025 10:25:45 -0700 Subject: [PATCH 05/15] Enabled parameter documentation order rule. --- build/Source.ruleset | 2 -- src/Autofac/Builder/RegistrationBuilder.cs | 2 +- .../OpenGenericRegistrationExtensions.cs | 6 ++--- .../RegistrationExtensions.Decorators.cs | 6 +++-- src/Autofac/RegistrationExtensions.Keyed.cs | 2 +- src/Autofac/RegistrationExtensions.Named.cs | 2 +- src/Autofac/RegistrationExtensions.cs | 2 +- src/Autofac/ResolutionExtensions.cs | 26 +++++++++---------- src/Autofac/ResolutionValueExtensions.cs | 8 +++--- ...ServiceMiddlewareRegistrationExtensions.cs | 4 +-- 10 files changed, 30 insertions(+), 30 deletions(-) diff --git a/build/Source.ruleset b/build/Source.ruleset index 00ee46790..43321565d 100644 --- a/build/Source.ruleset +++ b/build/Source.ruleset @@ -40,8 +40,6 @@ - - diff --git a/src/Autofac/Builder/RegistrationBuilder.cs b/src/Autofac/Builder/RegistrationBuilder.cs index 9b441aa20..abfa91a35 100644 --- a/src/Autofac/Builder/RegistrationBuilder.cs +++ b/src/Autofac/Builder/RegistrationBuilder.cs @@ -43,8 +43,8 @@ public static IRegistrationBuilder /// Creates a registration builder for the provided delegate. /// - /// Delegate to register. /// Most specific type return value of delegate can be cast to. + /// Delegate to register. /// A registration builder. public static IRegistrationBuilder ForDelegate(Type limitType, Func, object> @delegate) { diff --git a/src/Autofac/Features/OpenGenerics/OpenGenericRegistrationExtensions.cs b/src/Autofac/Features/OpenGenerics/OpenGenericRegistrationExtensions.cs index b0772758f..a672675a2 100644 --- a/src/Autofac/Features/OpenGenerics/OpenGenericRegistrationExtensions.cs +++ b/src/Autofac/Features/OpenGenerics/OpenGenericRegistrationExtensions.cs @@ -112,14 +112,14 @@ public static IRegistrationBuilder and parameters must be different values. /// /// Container builder. - /// Service type being decorated. Must be an open generic type. - /// Service key or name associated with the components being decorated. - /// Service key or name given to the decorated components. /// /// The type of the decorator. Must be an open generic type, and accept a /// parameter of type , which will be /// set to the instance being decorated. /// + /// Service type being decorated. Must be an open generic type. + /// Service key or name associated with the components being decorated. + /// Service key or name given to the decorated components. /// The decorator registration for further configuration. public static IRegistrationBuilder RegisterGenericDecorator(ContainerBuilder builder, Type decoratorType, Type decoratedServiceType, object fromKey, object? toKey) diff --git a/src/Autofac/RegistrationExtensions.Decorators.cs b/src/Autofac/RegistrationExtensions.Decorators.cs index 6e3e9d0c5..a12e4e5d9 100644 --- a/src/Autofac/RegistrationExtensions.Decorators.cs +++ b/src/Autofac/RegistrationExtensions.Decorators.cs @@ -22,11 +22,13 @@ public static partial class RegistrationExtensions /// The and parameters must be different values. /// /// Container builder. + /// + /// The type of the decorator. Must be an open generic type, and accept a parameter + /// of type , which will be set to the instance being decorated. + /// /// Service type being decorated. Must be an open generic type. /// Service key or name associated with the components being decorated. /// Service key or name given to the decorated components. - /// The type of the decorator. Must be an open generic type, and accept a parameter - /// of type , which will be set to the instance being decorated. /// The decorator registration for continued configuration. public static IRegistrationBuilder RegisterGenericDecorator( diff --git a/src/Autofac/RegistrationExtensions.Keyed.cs b/src/Autofac/RegistrationExtensions.Keyed.cs index 360fbd728..5b8800246 100644 --- a/src/Autofac/RegistrationExtensions.Keyed.cs +++ b/src/Autofac/RegistrationExtensions.Keyed.cs @@ -35,8 +35,8 @@ public static IRegistrationBuilderActivator data type. /// Registration style. /// Registration to set service mapping on. - /// Service type provided by the component. /// Function mapping types to service keys. + /// Service type provided by the component. /// Registration builder allowing the registration to be configured. public static IRegistrationBuilder Keyed( diff --git a/src/Autofac/RegistrationExtensions.Named.cs b/src/Autofac/RegistrationExtensions.Named.cs index b16275570..cdd102639 100644 --- a/src/Autofac/RegistrationExtensions.Named.cs +++ b/src/Autofac/RegistrationExtensions.Named.cs @@ -35,8 +35,8 @@ public static IRegistrationBuilderActivator data type. /// Registration style. /// Registration to set service mapping on. - /// Service type provided by the component. /// Function mapping types to service names. + /// Service type provided by the component. /// Registration builder allowing the registration to be configured. public static IRegistrationBuilder Named( diff --git a/src/Autofac/RegistrationExtensions.cs b/src/Autofac/RegistrationExtensions.cs index 7cf3925fc..646c86ba6 100644 --- a/src/Autofac/RegistrationExtensions.cs +++ b/src/Autofac/RegistrationExtensions.cs @@ -115,8 +115,8 @@ public static IRegistrationBuilder /// Register a component to be created through reflection. /// - /// The type of the component implementation. /// Container builder. + /// The type of the component implementation. /// Registration builder allowing the registration to be configured. public static IRegistrationBuilder RegisterType(this ContainerBuilder builder, [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] Type implementationType) diff --git a/src/Autofac/ResolutionExtensions.cs b/src/Autofac/ResolutionExtensions.cs index bf76a3323..6555c7c51 100644 --- a/src/Autofac/ResolutionExtensions.cs +++ b/src/Autofac/ResolutionExtensions.cs @@ -324,8 +324,8 @@ public static object Resolve(this IComponentContext context, Type serviceType) /// Retrieve a service from the context. /// /// The context from which to resolve the service. - /// Parameters for the service. /// The service type. + /// Parameters for the service. /// /// The component instance that provides the service. /// @@ -340,8 +340,8 @@ public static object Resolve(this IComponentContext context, Type serviceType, I /// Retrieve a service from the context. /// /// The context from which to resolve the service. - /// Parameters for the service. /// The service type. + /// Parameters for the service. /// /// The component instance that provides the service. /// @@ -528,9 +528,9 @@ public static object ResolveNamed(this IComponentContext context, string service /// Retrieve a service from the context. /// /// The context from which to resolve the service. - /// Parameters for the service. /// The service name. /// Type of the service. + /// Parameters for the service. /// /// The component instance that provides the service. /// @@ -545,9 +545,9 @@ public static object ResolveNamed(this IComponentContext context, string service /// Retrieve a service from the context. /// /// The context from which to resolve the service. - /// Parameters for the service. /// The service name. /// Type of the service. + /// Parameters for the service. /// /// The component instance that provides the service. /// @@ -628,8 +628,8 @@ public static object ResolveNamed(this IComponentContext context, string service /// registered. /// /// The context from which to resolve the service. - /// Parameters for the service. /// The type of the service. + /// Parameters for the service. /// /// The component instance that provides the service, or null. /// @@ -644,8 +644,8 @@ public static object ResolveNamed(this IComponentContext context, string service /// registered. /// /// The context from which to resolve the service. - /// Parameters for the service. /// The type of the service. + /// Parameters for the service. /// /// The component instance that provides the service, or null. /// @@ -677,8 +677,8 @@ public static object ResolveNamed(this IComponentContext context, string service /// registered. /// /// The context from which to resolve the service. - /// Parameters for the service. /// The name of the service. + /// Parameters for the service. /// The service to resolve. /// /// The component instance that provides the service, or null. @@ -695,8 +695,8 @@ public static object ResolveNamed(this IComponentContext context, string service /// registered. /// /// The context from which to resolve the service. - /// Parameters for the service. /// The key of the service. + /// Parameters for the service. /// The service to resolve. /// /// The component instance that provides the service, or null. @@ -730,8 +730,8 @@ public static object ResolveNamed(this IComponentContext context, string service /// registered. /// /// The context from which to resolve the service. - /// Parameters for the service. /// The name of the service. + /// Parameters for the service. /// The service to resolve. /// /// The component instance that provides the service, or null. @@ -748,8 +748,8 @@ public static object ResolveNamed(this IComponentContext context, string service /// registered. /// /// The context from which to resolve the service. - /// Parameters for the service. /// The name of the service. + /// Parameters for the service. /// The service to resolve. /// /// The component instance that provides the service, or null. @@ -843,8 +843,8 @@ public static object ResolveService(this IComponentContext context, Service serv /// Retrieve a service from the context. /// /// The context from which to resolve the service. - /// Parameters for the service. /// The service to resolve. + /// Parameters for the service. /// /// The component instance that provides the service. /// @@ -874,8 +874,8 @@ public static object ResolveService(this IComponentContext context, Service serv /// Retrieve a service from the context. /// /// The context from which to resolve the service. - /// Parameters for the service. /// The service to resolve. + /// Parameters for the service. /// /// The component instance that provides the service. /// @@ -1037,8 +1037,8 @@ public static bool TryResolveService(this IComponentContext context, Service ser /// /// The context from which to resolve the service. /// The service to resolve. - /// The resulting component instance providing the service, or null. /// The parameters. + /// The resulting component instance providing the service, or null. /// /// True if a component providing the service is available. /// diff --git a/src/Autofac/ResolutionValueExtensions.cs b/src/Autofac/ResolutionValueExtensions.cs index e9cd4a68e..3af7fb95d 100644 --- a/src/Autofac/ResolutionValueExtensions.cs +++ b/src/Autofac/ResolutionValueExtensions.cs @@ -85,8 +85,8 @@ public static class ResolutionValueExtensions /// registered. /// /// The context from which to resolve the service. - /// Parameters for the service. /// The name of the service. + /// Parameters for the service. /// The service to resolve. /// /// The component instance that provides the service, or null. @@ -103,8 +103,8 @@ public static class ResolutionValueExtensions /// registered. /// /// The context from which to resolve the service. - /// Parameters for the service. /// The key of the service. + /// Parameters for the service. /// The service to resolve. /// /// The component instance that provides the service, or null. @@ -138,8 +138,8 @@ public static class ResolutionValueExtensions /// registered. /// /// The context from which to resolve the service. - /// Parameters for the service. /// The name of the service. + /// Parameters for the service. /// The service to resolve. /// /// The component instance that provides the service, or null. @@ -156,8 +156,8 @@ public static class ResolutionValueExtensions /// registered. /// /// The context from which to resolve the service. - /// Parameters for the service. /// The name of the service. + /// Parameters for the service. /// The service to resolve. /// /// The component instance that provides the service, or null. diff --git a/src/Autofac/ServiceMiddlewareRegistrationExtensions.cs b/src/Autofac/ServiceMiddlewareRegistrationExtensions.cs index cdeb50e79..9fb7f4568 100644 --- a/src/Autofac/ServiceMiddlewareRegistrationExtensions.cs +++ b/src/Autofac/ServiceMiddlewareRegistrationExtensions.cs @@ -94,12 +94,12 @@ public static void RegisterServiceMiddleware(this ContainerBuilder bui /// The container builder. /// A description for the middleware; this will show up in any resolve tracing. /// The phase of the pipeline the middleware should run at. + /// The insertion mode of the middleware (start or end of phase). /// /// A callback invoked to run your middleware. /// This callback takes a , containing the context for the resolve request, plus /// a callback to invoke to continue the pipeline. /// - /// The insertion mode of the middleware (start or end of phase). public static void RegisterServiceMiddleware(this ContainerBuilder builder, string descriptor, PipelinePhase phase, MiddlewareInsertionMode insertionMode, Action> callback) { builder.RegisterServiceMiddleware(typeof(TService), new DelegateMiddleware(descriptor, phase, callback), insertionMode); @@ -145,12 +145,12 @@ public static void RegisterServiceMiddleware(this ContainerBuilder builder, Type /// The service type. /// A description for the middleware; this will show up in any resolve tracing. /// The phase of the pipeline the middleware should run at. + /// The insertion mode of the middleware (start or end of phase). /// /// A callback invoked to run your middleware. /// This callback takes a , containing the context for the resolve request, plus /// a callback to invoke to continue the pipeline. /// - /// The insertion mode of the middleware (start or end of phase). public static void RegisterServiceMiddleware(this ContainerBuilder builder, Type serviceType, string descriptor, PipelinePhase phase, MiddlewareInsertionMode insertionMode, Action> callback) { builder.RegisterServiceMiddleware(serviceType, new DelegateMiddleware(descriptor, phase, callback), insertionMode); From d45acd351662eab0128e83ab8389470ba5eb8766 Mon Sep 17 00:00:00 2001 From: Travis Illig Date: Thu, 18 Sep 2025 10:40:38 -0700 Subject: [PATCH 06/15] Enabled no empty documentation rule. --- build/Source.ruleset | 6 - .../Core/RegistrationSourceAddedEventArgs.cs | 1 - src/Autofac/Core/ResolvedParameter.cs | 2 - src/Autofac/IComponentContext.cs | 8 +- src/Autofac/ResolutionExtensions.cs | 260 +++++++++++++----- src/Autofac/ResolutionValueExtensions.cs | 40 ++- 6 files changed, 231 insertions(+), 86 deletions(-) diff --git a/build/Source.ruleset b/build/Source.ruleset index 43321565d..eb3960a07 100644 --- a/build/Source.ruleset +++ b/build/Source.ruleset @@ -34,17 +34,11 @@ - - - - - - diff --git a/src/Autofac/Core/RegistrationSourceAddedEventArgs.cs b/src/Autofac/Core/RegistrationSourceAddedEventArgs.cs index 25fe4c4ee..92b222199 100644 --- a/src/Autofac/Core/RegistrationSourceAddedEventArgs.cs +++ b/src/Autofac/Core/RegistrationSourceAddedEventArgs.cs @@ -15,7 +15,6 @@ public class RegistrationSourceAddedEventArgs : EventArgs /// /// The registry to which the source was added. /// The source that was added. - /// public RegistrationSourceAddedEventArgs(IComponentRegistryBuilder componentRegistry, IRegistrationSource registrationSource) { ComponentRegistry = componentRegistry ?? throw new ArgumentNullException(nameof(componentRegistry)); diff --git a/src/Autofac/Core/ResolvedParameter.cs b/src/Autofac/Core/ResolvedParameter.cs index eb0173d24..c2f5c17ad 100644 --- a/src/Autofac/Core/ResolvedParameter.cs +++ b/src/Autofac/Core/ResolvedParameter.cs @@ -64,8 +64,6 @@ public override bool CanSupplyValue(ParameterInfo pi, IComponentContext context, /// The type of the parameter to match. /// The name of the matching service to resolve. /// A configured instance. - /// - /// public static ResolvedParameter ForNamed(string serviceName) { if (serviceName == null) diff --git a/src/Autofac/IComponentContext.cs b/src/Autofac/IComponentContext.cs index a8aa25936..b462652fb 100644 --- a/src/Autofac/IComponentContext.cs +++ b/src/Autofac/IComponentContext.cs @@ -25,7 +25,11 @@ public interface IComponentContext /// /// The component instance. /// - /// - /// + /// + /// Thrown if the requested component is not registered. + /// + /// + /// Thrown if the component cannot be resolved. + /// object ResolveComponent(in ResolveRequest request); } diff --git a/src/Autofac/ResolutionExtensions.cs b/src/Autofac/ResolutionExtensions.cs index 6555c7c51..62bfeb10a 100644 --- a/src/Autofac/ResolutionExtensions.cs +++ b/src/Autofac/ResolutionExtensions.cs @@ -263,8 +263,12 @@ public static bool IsRegisteredWithName(this IComponentContext context, string s /// The service to retrieve. /// The context from which to resolve the service. /// The component instance that provides the service. - /// - /// + /// + /// Thrown if the requested component is not registered. + /// + /// + /// Thrown if the component cannot be resolved. + /// public static TService Resolve(this IComponentContext context) where TService : notnull { @@ -280,8 +284,12 @@ public static TService Resolve(this IComponentContext context) /// /// The component instance that provides the service. /// - /// - /// + /// + /// Thrown if the requested component is not registered. + /// + /// + /// Thrown if the component cannot be resolved. + /// public static TService Resolve(this IComponentContext context, IEnumerable parameters) where TService : notnull { @@ -297,8 +305,12 @@ public static TService Resolve(this IComponentContext context, IEnumer /// /// The component instance that provides the service. /// - /// - /// + /// + /// Thrown if the requested component is not registered. + /// + /// + /// Thrown if the component cannot be resolved. + /// public static TService Resolve(this IComponentContext context, params Parameter[] parameters) where TService : notnull { @@ -313,8 +325,12 @@ public static TService Resolve(this IComponentContext context, params /// /// The component instance that provides the service. /// - /// - /// + /// + /// Thrown if the requested component is not registered. + /// + /// + /// Thrown if the component cannot be resolved. + /// public static object Resolve(this IComponentContext context, Type serviceType) { return Resolve(context, serviceType, ResolveRequest.NoParameters); @@ -329,8 +345,12 @@ public static object Resolve(this IComponentContext context, Type serviceType) /// /// The component instance that provides the service. /// - /// - /// + /// + /// Thrown if the requested component is not registered. + /// + /// + /// Thrown if the component cannot be resolved. + /// public static object Resolve(this IComponentContext context, Type serviceType, IEnumerable parameters) { return ResolveService(context, new TypedService(serviceType), parameters); @@ -345,8 +365,12 @@ public static object Resolve(this IComponentContext context, Type serviceType, I /// /// The component instance that provides the service. /// - /// - /// + /// + /// Thrown if the requested component is not registered. + /// + /// + /// Thrown if the component cannot be resolved. + /// public static object Resolve(this IComponentContext context, Type serviceType, params Parameter[] parameters) { return context.Resolve(serviceType, (IEnumerable)parameters); @@ -361,8 +385,12 @@ public static object Resolve(this IComponentContext context, Type serviceType, p /// /// The component instance that provides the service. /// - /// - /// + /// + /// Thrown if the requested component is not registered. + /// + /// + /// Thrown if the component cannot be resolved. + /// public static TService ResolveKeyed(this IComponentContext context, object serviceKey) where TService : notnull { @@ -379,8 +407,12 @@ public static TService ResolveKeyed(this IComponentContext context, ob /// /// The component instance that provides the service. /// - /// - /// + /// + /// Thrown if the requested component is not registered. + /// + /// + /// Thrown if the component cannot be resolved. + /// public static TService ResolveKeyed(this IComponentContext context, object serviceKey, IEnumerable parameters) where TService : notnull { @@ -397,8 +429,12 @@ public static TService ResolveKeyed(this IComponentContext context, ob /// /// The component instance that provides the service. /// - /// - /// + /// + /// Thrown if the requested component is not registered. + /// + /// + /// Thrown if the component cannot be resolved. + /// public static TService ResolveKeyed(this IComponentContext context, object serviceKey, params Parameter[] parameters) where TService : notnull { @@ -414,8 +450,12 @@ public static TService ResolveKeyed(this IComponentContext context, ob /// /// The component instance that provides the service. /// - /// - /// + /// + /// Thrown if the requested component is not registered. + /// + /// + /// Thrown if the component cannot be resolved. + /// public static object ResolveKeyed(this IComponentContext context, object serviceKey, Type serviceType) { return ResolveKeyed(context, serviceKey, serviceType, ResolveRequest.NoParameters); @@ -431,8 +471,12 @@ public static object ResolveKeyed(this IComponentContext context, object service /// /// The component instance that provides the service. /// - /// - /// + /// + /// Thrown if the requested component is not registered. + /// + /// + /// Thrown if the component cannot be resolved. + /// public static object ResolveKeyed(this IComponentContext context, object serviceKey, Type serviceType, IEnumerable parameters) { return ResolveService(context, new KeyedService(serviceKey, serviceType), parameters); @@ -448,8 +492,12 @@ public static object ResolveKeyed(this IComponentContext context, object service /// /// The component instance that provides the service. /// - /// - /// + /// + /// Thrown if the requested component is not registered. + /// + /// + /// Thrown if the component cannot be resolved. + /// public static object ResolveKeyed(this IComponentContext context, object serviceKey, Type serviceType, params Parameter[] parameters) { return context.ResolveKeyed(serviceKey, serviceType, (IEnumerable)parameters); @@ -464,8 +512,12 @@ public static object ResolveKeyed(this IComponentContext context, object service /// /// The component instance that provides the service. /// - /// - /// + /// + /// Thrown if the requested component is not registered. + /// + /// + /// Thrown if the component cannot be resolved. + /// public static TService ResolveNamed(this IComponentContext context, string serviceName) where TService : notnull { @@ -482,8 +534,12 @@ public static TService ResolveNamed(this IComponentContext context, st /// /// The component instance that provides the service. /// - /// - /// + /// + /// Thrown if the requested component is not registered. + /// + /// + /// Thrown if the component cannot be resolved. + /// public static TService ResolveNamed(this IComponentContext context, string serviceName, IEnumerable parameters) where TService : notnull { @@ -500,8 +556,12 @@ public static TService ResolveNamed(this IComponentContext context, st /// /// The component instance that provides the service. /// - /// - /// + /// + /// Thrown if the requested component is not registered. + /// + /// + /// Thrown if the component cannot be resolved. + /// public static TService ResolveNamed(this IComponentContext context, string serviceName, params Parameter[] parameters) where TService : notnull { @@ -517,8 +577,12 @@ public static TService ResolveNamed(this IComponentContext context, st /// /// The component instance that provides the service. /// - /// - /// + /// + /// Thrown if the requested component is not registered. + /// + /// + /// Thrown if the component cannot be resolved. + /// public static object ResolveNamed(this IComponentContext context, string serviceName, Type serviceType) { return ResolveNamed(context, serviceName, serviceType, ResolveRequest.NoParameters); @@ -534,8 +598,12 @@ public static object ResolveNamed(this IComponentContext context, string service /// /// The component instance that provides the service. /// - /// - /// + /// + /// Thrown if the requested component is not registered. + /// + /// + /// Thrown if the component cannot be resolved. + /// public static object ResolveNamed(this IComponentContext context, string serviceName, Type serviceType, IEnumerable parameters) { return ResolveService(context, new KeyedService(serviceName, serviceType), parameters); @@ -551,8 +619,12 @@ public static object ResolveNamed(this IComponentContext context, string service /// /// The component instance that provides the service. /// - /// - /// + /// + /// Thrown if the requested component is not registered. + /// + /// + /// Thrown if the component cannot be resolved. + /// public static object ResolveNamed(this IComponentContext context, string serviceName, Type serviceType, params Parameter[] parameters) { return context.ResolveNamed(serviceName, serviceType, (IEnumerable)parameters); @@ -567,7 +639,9 @@ public static object ResolveNamed(this IComponentContext context, string service /// /// The component instance that provides the service, or null. /// - /// + /// + /// Thrown if the component cannot be resolved. + /// public static TService? ResolveOptional(this IComponentContext context) where TService : class { @@ -584,7 +658,9 @@ public static object ResolveNamed(this IComponentContext context, string service /// /// The component instance that provides the service, or null. /// - /// + /// + /// Thrown if the component cannot be resolved. + /// public static TService? ResolveOptional(this IComponentContext context, IEnumerable parameters) where TService : class { @@ -601,7 +677,9 @@ public static object ResolveNamed(this IComponentContext context, string service /// /// The component instance that provides the service, or null. /// - /// + /// + /// Thrown if the component cannot be resolved. + /// public static TService? ResolveOptional(this IComponentContext context, params Parameter[] parameters) where TService : class { @@ -617,7 +695,9 @@ public static object ResolveNamed(this IComponentContext context, string service /// /// The component instance that provides the service, or null. /// - /// + /// + /// Thrown if the component cannot be resolved. + /// public static object? ResolveOptional(this IComponentContext context, Type serviceType) { return ResolveOptional(context, serviceType, ResolveRequest.NoParameters); @@ -633,7 +713,9 @@ public static object ResolveNamed(this IComponentContext context, string service /// /// The component instance that provides the service, or null. /// - /// + /// + /// Thrown if the component cannot be resolved. + /// public static object? ResolveOptional(this IComponentContext context, Type serviceType, IEnumerable parameters) { return ResolveOptionalService(context, new TypedService(serviceType), parameters); @@ -649,7 +731,9 @@ public static object ResolveNamed(this IComponentContext context, string service /// /// The component instance that provides the service, or null. /// - /// + /// + /// Thrown if the component cannot be resolved. + /// public static object? ResolveOptional(this IComponentContext context, Type serviceType, params Parameter[] parameters) { return context.ResolveOptional(serviceType, (IEnumerable)parameters); @@ -665,7 +749,9 @@ public static object ResolveNamed(this IComponentContext context, string service /// /// The component instance that provides the service, or null. /// - /// + /// + /// Thrown if the component cannot be resolved. + /// public static TService? ResolveOptionalKeyed(this IComponentContext context, object serviceKey) where TService : class { @@ -683,7 +769,9 @@ public static object ResolveNamed(this IComponentContext context, string service /// /// The component instance that provides the service, or null. /// - /// + /// + /// Thrown if the component cannot be resolved. + /// public static TService? ResolveOptionalKeyed(this IComponentContext context, object serviceKey, IEnumerable parameters) where TService : class { @@ -701,7 +789,9 @@ public static object ResolveNamed(this IComponentContext context, string service /// /// The component instance that provides the service, or null. /// - /// + /// + /// Thrown if the component cannot be resolved. + /// public static TService? ResolveOptionalKeyed(this IComponentContext context, object serviceKey, params Parameter[] parameters) where TService : class { @@ -718,7 +808,9 @@ public static object ResolveNamed(this IComponentContext context, string service /// /// The component instance that provides the service, or null. /// - /// + /// + /// Thrown if the component cannot be resolved. + /// public static TService? ResolveOptionalNamed(this IComponentContext context, string serviceName) where TService : class { @@ -736,7 +828,9 @@ public static object ResolveNamed(this IComponentContext context, string service /// /// The component instance that provides the service, or null. /// - /// + /// + /// Thrown if the component cannot be resolved. + /// public static TService? ResolveOptionalNamed(this IComponentContext context, string serviceName, IEnumerable parameters) where TService : class { @@ -754,7 +848,9 @@ public static object ResolveNamed(this IComponentContext context, string service /// /// The component instance that provides the service, or null. /// - /// + /// + /// Thrown if the component cannot be resolved. + /// public static TService? ResolveOptionalNamed(this IComponentContext context, string serviceName, params Parameter[] parameters) where TService : class { @@ -770,7 +866,9 @@ public static object ResolveNamed(this IComponentContext context, string service /// /// The component instance that provides the service, or null. /// - /// + /// + /// Thrown if the component cannot be resolved. + /// public static object? ResolveOptionalService(this IComponentContext context, Service service) { return ResolveOptionalService(context, service, ResolveRequest.NoParameters); @@ -786,7 +884,9 @@ public static object ResolveNamed(this IComponentContext context, string service /// /// The component instance that provides the service, or null. /// - /// + /// + /// Thrown if the component cannot be resolved. + /// public static object? ResolveOptionalService(this IComponentContext context, Service service, IEnumerable parameters) { if (context == null) @@ -818,7 +918,9 @@ public static object ResolveNamed(this IComponentContext context, string service /// /// The component instance that provides the service, or null. /// - /// + /// + /// Thrown if the component cannot be resolved. + /// public static object? ResolveOptionalService(this IComponentContext context, Service service, params Parameter[] parameters) { return context.ResolveOptionalService(service, (IEnumerable)parameters); @@ -832,8 +934,12 @@ public static object ResolveNamed(this IComponentContext context, string service /// /// The component instance that provides the service. /// - /// - /// + /// + /// Thrown if the requested component is not registered. + /// + /// + /// Thrown if the component cannot be resolved. + /// public static object ResolveService(this IComponentContext context, Service service) { return ResolveService(context, service, ResolveRequest.NoParameters); @@ -848,8 +954,12 @@ public static object ResolveService(this IComponentContext context, Service serv /// /// The component instance that provides the service. /// - /// - /// + /// + /// Thrown if the requested component is not registered. + /// + /// + /// Thrown if the component cannot be resolved. + /// public static object ResolveService(this IComponentContext context, Service service, IEnumerable parameters) { if (service == null) @@ -879,8 +989,12 @@ public static object ResolveService(this IComponentContext context, Service serv /// /// The component instance that provides the service. /// - /// - /// + /// + /// Thrown if the requested component is not registered. + /// + /// + /// Thrown if the component cannot be resolved. + /// public static object ResolveService(this IComponentContext context, Service service, params Parameter[] parameters) { return context.ResolveService(service, (IEnumerable)parameters); @@ -895,7 +1009,9 @@ public static object ResolveService(this IComponentContext context, Service serv /// /// True if a component providing the service is available. /// - /// + /// + /// Thrown if the component cannot be resolved. + /// public static bool TryResolve(this IComponentContext context, [NotNullWhen(returnValue: true)] out T? instance) where T : class { @@ -923,7 +1039,9 @@ public static bool TryResolve(this IComponentContext context, [NotNullWhen(re /// /// True if a component providing the service is available. /// - /// + /// + /// Thrown if the component cannot be resolved. + /// public static bool TryResolve(this IComponentContext context, Type serviceType, [NotNullWhen(returnValue: true)] out object? instance) { return context.TryResolveService(new TypedService(serviceType), ResolveRequest.NoParameters, out instance); @@ -939,7 +1057,9 @@ public static bool TryResolve(this IComponentContext context, Type serviceType, /// /// True if a component providing the service is available. /// - /// + /// + /// Thrown if the component cannot be resolved. + /// public static bool TryResolveKeyed(this IComponentContext context, object serviceKey, [NotNullWhen(returnValue: true)] out T? instance) where T : class { @@ -967,7 +1087,9 @@ public static bool TryResolveKeyed(this IComponentContext context, object ser /// /// True if a component providing the service is available. /// - /// + /// + /// Thrown if the component cannot be resolved. + /// public static bool TryResolveKeyed(this IComponentContext context, object serviceKey, Type serviceType, [NotNullWhen(returnValue: true)] out object? instance) { return context.TryResolveService(new KeyedService(serviceKey, serviceType), ResolveRequest.NoParameters, out instance); @@ -983,7 +1105,9 @@ public static bool TryResolveKeyed(this IComponentContext context, object servic /// /// True if a component providing the service is available. /// - /// + /// + /// Thrown if the component cannot be resolved. + /// public static bool TryResolveNamed(this IComponentContext context, string serviceName, [NotNullWhen(returnValue: true)] out T? instance) where T : class { @@ -1011,7 +1135,9 @@ public static bool TryResolveNamed(this IComponentContext context, string ser /// /// True if a component providing the service is available. /// - /// + /// + /// Thrown if the component cannot be resolved. + /// public static bool TryResolveNamed(this IComponentContext context, string serviceName, Type serviceType, [NotNullWhen(returnValue: true)] out object? instance) { return context.TryResolveService(new KeyedService(serviceName, serviceType), ResolveRequest.NoParameters, out instance); @@ -1026,7 +1152,9 @@ public static bool TryResolveNamed(this IComponentContext context, string servic /// /// True if a component providing the service is available. /// - /// + /// + /// Thrown if the component cannot be resolved. + /// public static bool TryResolveService(this IComponentContext context, Service service, [NotNullWhen(returnValue: true)] out object? instance) { return context.TryResolveService(service, ResolveRequest.NoParameters, out instance); @@ -1042,7 +1170,9 @@ public static bool TryResolveService(this IComponentContext context, Service ser /// /// True if a component providing the service is available. /// - /// + /// + /// Thrown if the component cannot be resolved. + /// /// /// Thrown if is . /// diff --git a/src/Autofac/ResolutionValueExtensions.cs b/src/Autofac/ResolutionValueExtensions.cs index 3af7fb95d..26d40c124 100644 --- a/src/Autofac/ResolutionValueExtensions.cs +++ b/src/Autofac/ResolutionValueExtensions.cs @@ -22,7 +22,9 @@ public static class ResolutionValueExtensions /// /// The component instance that provides the service, or null. /// - /// + /// + /// Thrown if the component cannot be resolved. + /// public static TService? ResolveOptional(this IComponentContext context) where TService : struct { @@ -39,7 +41,9 @@ public static class ResolutionValueExtensions /// /// The component instance that provides the service, or null. /// - /// + /// + /// Thrown if the component cannot be resolved. + /// public static TService? ResolveOptional(this IComponentContext context, IEnumerable parameters) where TService : struct { @@ -56,7 +60,9 @@ public static class ResolutionValueExtensions /// /// The component instance that provides the service, or null. /// - /// + /// + /// Thrown if the component cannot be resolved. + /// public static TService? ResolveOptional(this IComponentContext context, params Parameter[] parameters) where TService : struct { @@ -73,7 +79,9 @@ public static class ResolutionValueExtensions /// /// The component instance that provides the service, or null. /// - /// + /// + /// Thrown if the component cannot be resolved. + /// public static TService? ResolveOptionalKeyed(this IComponentContext context, object serviceKey) where TService : struct { @@ -91,7 +99,9 @@ public static class ResolutionValueExtensions /// /// The component instance that provides the service, or null. /// - /// + /// + /// Thrown if the component cannot be resolved. + /// public static TService? ResolveOptionalKeyed(this IComponentContext context, object serviceKey, IEnumerable parameters) where TService : struct { @@ -109,7 +119,9 @@ public static class ResolutionValueExtensions /// /// The component instance that provides the service, or null. /// - /// + /// + /// Thrown if the component cannot be resolved. + /// public static TService? ResolveOptionalKeyed(this IComponentContext context, object serviceKey, params Parameter[] parameters) where TService : struct { @@ -126,7 +138,9 @@ public static class ResolutionValueExtensions /// /// The component instance that provides the service, or null. /// - /// + /// + /// Thrown if the component cannot be resolved. + /// public static TService? ResolveOptionalNamed(this IComponentContext context, string serviceName) where TService : struct { @@ -144,7 +158,9 @@ public static class ResolutionValueExtensions /// /// The component instance that provides the service, or null. /// - /// + /// + /// Thrown if the component cannot be resolved. + /// public static TService? ResolveOptionalNamed(this IComponentContext context, string serviceName, IEnumerable parameters) where TService : struct { @@ -162,7 +178,9 @@ public static class ResolutionValueExtensions /// /// The component instance that provides the service, or null. /// - /// + /// + /// Thrown if the component cannot be resolved. + /// public static TService? ResolveOptionalNamed(this IComponentContext context, string serviceName, params Parameter[] parameters) where TService : struct { @@ -178,7 +196,9 @@ public static class ResolutionValueExtensions /// /// True if a component providing the service is available. /// - /// + /// + /// Thrown if the component cannot be resolved. + /// public static bool TryResolve(this IComponentContext context, [NotNullWhen(returnValue: true)] out T? instance) where T : struct { From f1e4473ce2ebbfe4e3b8b44905eb422a994db745 Mon Sep 17 00:00:00 2001 From: Travis Illig Date: Thu, 18 Sep 2025 10:43:43 -0700 Subject: [PATCH 07/15] Enabled readonly field ordering. --- build/Source.ruleset | 2 -- src/Autofac/Builder/RegistrationData.cs | 4 +--- src/Autofac/Core/Disposer.cs | 10 +++++----- .../Core/Registration/ServiceRegistrationInfo.cs | 12 ++++++------ src/Autofac/Core/Resolving/ResolveOperation.cs | 4 +--- 5 files changed, 13 insertions(+), 19 deletions(-) diff --git a/build/Source.ruleset b/build/Source.ruleset index eb3960a07..20cbc2dbf 100644 --- a/build/Source.ruleset +++ b/build/Source.ruleset @@ -34,8 +34,6 @@ - - diff --git a/src/Autofac/Builder/RegistrationData.cs b/src/Autofac/Builder/RegistrationData.cs index 4e5ba29bf..3617323ea 100644 --- a/src/Autofac/Builder/RegistrationData.cs +++ b/src/Autofac/Builder/RegistrationData.cs @@ -14,11 +14,9 @@ namespace Autofac.Builder; /// public class RegistrationData { + private readonly HashSet _services = []; private bool _defaultServiceOverridden; private Service _defaultService; - - private readonly HashSet _services = []; - private IComponentLifetime _lifetime = CurrentScopeLifetime.Instance; /// diff --git a/src/Autofac/Core/Disposer.cs b/src/Autofac/Core/Disposer.cs index 0ca084000..b17e79e9b 100644 --- a/src/Autofac/Core/Disposer.cs +++ b/src/Autofac/Core/Disposer.cs @@ -12,15 +12,15 @@ namespace Autofac.Core; /// internal class Disposer : Disposable, IDisposer { + // Need to use a semaphore instead of a simple object to lock on, because + // we need to synchronize an awaitable block. + private readonly SemaphoreSlim _synchRoot = new(1, 1); + /// /// Contents all implement IDisposable or IAsyncDisposable. /// private Stack _items = new(); - // Need to use a semaphore instead of a simple object to lock on, because - // we need to synchronise an awaitable block. - private readonly SemaphoreSlim _synchRoot = new(1, 1); - /// /// Releases unmanaged and - optionally - managed resources. /// @@ -48,7 +48,7 @@ protected override void Dispose(bool disposing) // Type only implements IAsyncDisposable. We will need to do sync-over-async. // We want to ensure we lose all context here, because if we don't we can deadlock. - // So we push this disposal onto the threadpool. + // So we push this disposal onto the thread pool. Task.Run(async () => await asyncDisposable.DisposeAsync().ConfigureAwait(false)) .ConfigureAwait(false) .GetAwaiter().GetResult(); diff --git a/src/Autofac/Core/Registration/ServiceRegistrationInfo.cs b/src/Autofac/Core/Registration/ServiceRegistrationInfo.cs index 2f3250204..ac4d93515 100644 --- a/src/Autofac/Core/Registration/ServiceRegistrationInfo.cs +++ b/src/Autofac/Core/Registration/ServiceRegistrationInfo.cs @@ -11,18 +11,18 @@ namespace Autofac.Core.Registration; /// internal class ServiceRegistrationInfo : IResolvePipelineBuilder { - private volatile bool _isInitialized; - - private readonly Service _service; - - private IComponentRegistration? _fixedRegistration; - /// /// List of implicit default service implementations. Overriding default implementations are appended to the end, /// so the enumeration should begin from the end too, and the most default implementation comes last. /// private readonly List _defaultImplementations = new(); + private readonly Service _service; + + private volatile bool _isInitialized; + + private IComponentRegistration? _fixedRegistration; + /// /// List of service implementations coming from sources. Sources have priority over preserve-default implementations. /// Implementations from sources are enumerated in preserve-default order, so the most default implementation comes first. diff --git a/src/Autofac/Core/Resolving/ResolveOperation.cs b/src/Autofac/Core/Resolving/ResolveOperation.cs index 94b418fc4..7c1030987 100644 --- a/src/Autofac/Core/Resolving/ResolveOperation.cs +++ b/src/Autofac/Core/Resolving/ResolveOperation.cs @@ -14,11 +14,9 @@ namespace Autofac.Core.Resolving; /// internal sealed class ResolveOperation : IDependencyTrackingResolveOperation { + private readonly List _successfulRequests = new(SuccessListInitialCapacity); private const int SuccessListInitialCapacity = 32; private bool _ended; - - private readonly List _successfulRequests = new(SuccessListInitialCapacity); - private int _nextCompleteSuccessfulRequestStartPos; /// From 8a8d1ac3fc1734f73451038a0ff612333f07f06e Mon Sep 17 00:00:00 2001 From: Travis Illig Date: Thu, 18 Sep 2025 10:45:23 -0700 Subject: [PATCH 08/15] Enabled const ordering. --- .vscode/settings.json | 1 + build/Source.ruleset | 2 -- src/Autofac/Builder/BuildCallbackManager.cs | 4 ++-- .../Core/Registration/ComponentRegistration.cs | 12 ++++++------ src/Autofac/Core/Resolving/ResolveOperation.cs | 2 +- src/Autofac/Core/Resolving/SegmentedStack.cs | 3 +-- 6 files changed, 11 insertions(+), 13 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 5229de514..de3da713c 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -14,6 +14,7 @@ "netcoreapp", "netstandard", "notnull", + "parameterless", "paramref", "startable", "subclassing", diff --git a/build/Source.ruleset b/build/Source.ruleset index 20cbc2dbf..9a77eb228 100644 --- a/build/Source.ruleset +++ b/build/Source.ruleset @@ -30,8 +30,6 @@ - - diff --git a/src/Autofac/Builder/BuildCallbackManager.cs b/src/Autofac/Builder/BuildCallbackManager.cs index a74afe76f..ebe69af35 100644 --- a/src/Autofac/Builder/BuildCallbackManager.cs +++ b/src/Autofac/Builder/BuildCallbackManager.cs @@ -10,10 +10,10 @@ namespace Autofac.Builder; /// internal static class BuildCallbackManager { - private static readonly TypedService CallbackServiceType = new(typeof(BuildCallbackService)); - private const string BuildCallbacksExecutedKey = nameof(BuildCallbacksExecutedKey); + private static readonly TypedService CallbackServiceType = new(typeof(BuildCallbackService)); + /// /// Executes the newly-registered build callbacks for a given scope/container.. /// diff --git a/src/Autofac/Core/Registration/ComponentRegistration.cs b/src/Autofac/Core/Registration/ComponentRegistration.cs index 5fe589742..e4029abe0 100644 --- a/src/Autofac/Core/Registration/ComponentRegistration.cs +++ b/src/Autofac/Core/Registration/ComponentRegistration.cs @@ -14,12 +14,6 @@ namespace Autofac.Core.Registration; [SuppressMessage("Microsoft.ApiDesignGuidelines", "CA2213", Justification = "The target registration, if provided, is disposed elsewhere.")] public class ComponentRegistration : Disposable, IComponentRegistration { - private readonly IComponentRegistration? _target; - private readonly IResolvePipelineBuilder _lateBuildPipeline; - - private EventHandler? _pipelineBuildEvent; - private IResolvePipeline? _builtComponentPipeline; - /// /// Defines the options copied from a target registration onto this one. /// @@ -27,6 +21,12 @@ public class ComponentRegistration : Disposable, IComponentRegistration RegistrationOptions.ExcludeFromCollections | RegistrationOptions.DisableDecoration; + private readonly IComponentRegistration? _target; + private readonly IResolvePipelineBuilder _lateBuildPipeline; + + private EventHandler? _pipelineBuildEvent; + private IResolvePipeline? _builtComponentPipeline; + /// /// Initializes a new instance of the class. /// diff --git a/src/Autofac/Core/Resolving/ResolveOperation.cs b/src/Autofac/Core/Resolving/ResolveOperation.cs index 7c1030987..0ec78ea44 100644 --- a/src/Autofac/Core/Resolving/ResolveOperation.cs +++ b/src/Autofac/Core/Resolving/ResolveOperation.cs @@ -14,8 +14,8 @@ namespace Autofac.Core.Resolving; /// internal sealed class ResolveOperation : IDependencyTrackingResolveOperation { - private readonly List _successfulRequests = new(SuccessListInitialCapacity); private const int SuccessListInitialCapacity = 32; + private readonly List _successfulRequests = new(SuccessListInitialCapacity); private bool _ended; private int _nextCompleteSuccessfulRequestStartPos; diff --git a/src/Autofac/Core/Resolving/SegmentedStack.cs b/src/Autofac/Core/Resolving/SegmentedStack.cs index e75b774d2..c2f11d209 100644 --- a/src/Autofac/Core/Resolving/SegmentedStack.cs +++ b/src/Autofac/Core/Resolving/SegmentedStack.cs @@ -15,12 +15,11 @@ namespace Autofac.Core.Resolving; public sealed class SegmentedStack : IEnumerable where T : class { + private const int InitialCapacity = 16; private T[] _array; private int _next; private int _activeSegmentBase; - private const int InitialCapacity = 16; - /// /// Initializes a new instance of the class. /// From 6626736d4bb7213094d112b3c0dc8dc79eae5ced Mon Sep 17 00:00:00 2001 From: Travis Illig Date: Thu, 18 Sep 2025 10:49:11 -0700 Subject: [PATCH 09/15] Enabled static member ordering. --- build/Source.ruleset | 2 - .../Builder/ReflectionActivatorData.cs | 6 +- src/Autofac/ContainerBuilder.cs | 14 ++-- .../DefaultRegisteredServicesTracker.cs | 52 +++++++------- src/Autofac/Core/ResolvedParameter.cs | 72 +++++++++---------- .../BaseGenericResolveDelegateInvoker.cs | 48 ++++++------- .../Pipeline/ResolvePipelineBuilder.cs | 18 ++--- .../Diagnostics/DefaultDiagnosticTracer.cs | 4 +- .../GeneratedFactories/FactoryGenerator.cs | 4 +- 9 files changed, 109 insertions(+), 111 deletions(-) diff --git a/build/Source.ruleset b/build/Source.ruleset index 9a77eb228..48f55bce4 100644 --- a/build/Source.ruleset +++ b/build/Source.ruleset @@ -30,8 +30,6 @@ - - diff --git a/src/Autofac/Builder/ReflectionActivatorData.cs b/src/Autofac/Builder/ReflectionActivatorData.cs index f8c91e7a8..c82a67a3c 100644 --- a/src/Autofac/Builder/ReflectionActivatorData.cs +++ b/src/Autofac/Builder/ReflectionActivatorData.cs @@ -11,13 +11,13 @@ namespace Autofac.Builder; /// public class ReflectionActivatorData { + private static readonly IConstructorFinder DefaultConstructorFinder = new DefaultConstructorFinder(); + private static readonly IConstructorSelector DefaultConstructorSelector = new MostParametersConstructorSelector(); + private Type _implementer = default!; private IConstructorFinder _constructorFinder; private IConstructorSelector _constructorSelector; - private static readonly IConstructorFinder DefaultConstructorFinder = new DefaultConstructorFinder(); - private static readonly IConstructorSelector DefaultConstructorSelector = new MostParametersConstructorSelector(); - /// /// Initializes a new instance of the class. /// diff --git a/src/Autofac/ContainerBuilder.cs b/src/Autofac/ContainerBuilder.cs index 5bc5c5950..501c02cc3 100644 --- a/src/Autofac/ContainerBuilder.cs +++ b/src/Autofac/ContainerBuilder.cs @@ -197,6 +197,13 @@ internal void UpdateRegistry(IComponentRegistryBuilder componentRegistry) Build(componentRegistry, true); } + private static bool IsFirstContainerBuilder() + { + // First container will start with a value of 0, we will try and set it to 1; + // if the value is 0, it means it's the first builder. + return Interlocked.CompareExchange(ref _builderAlreadyAllocated, 1, 0) == 0; + } + private void Build(IComponentRegistryBuilder componentRegistry, bool excludeDefaultModules) { if (componentRegistry == null) @@ -233,11 +240,4 @@ private void RegisterDefaultAdapters(IComponentRegistryBuilder componentRegistry componentRegistry.AddRegistrationSource(new StronglyTypedMetaRegistrationSource()); componentRegistry.AddRegistrationSource(new GeneratedFactoryRegistrationSource()); } - - private static bool IsFirstContainerBuilder() - { - // First container will start with a value of 0, we will try and set it to 1; - // if the value is 0, it means it's the first builder. - return Interlocked.CompareExchange(ref _builderAlreadyAllocated, 1, 0) == 0; - } } diff --git a/src/Autofac/Core/Registration/DefaultRegisteredServicesTracker.cs b/src/Autofac/Core/Registration/DefaultRegisteredServicesTracker.cs index 70dfa946c..122082ee6 100644 --- a/src/Autofac/Core/Registration/DefaultRegisteredServicesTracker.cs +++ b/src/Autofac/Core/Registration/DefaultRegisteredServicesTracker.cs @@ -263,6 +263,32 @@ protected override async ValueTask DisposeAsync(bool disposing) // Do not call the base, otherwise the standard Dispose will fire. } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static IEnumerable ExcludeSource(IEnumerable sources, IRegistrationSource exclude) + { + foreach (var item in sources) + { + if (item != exclude) + { + yield return item; + } + } + } + + private static ServiceRegistrationInfo GetEphemeralServiceInfo(Dictionary ephemeralSet, Service service, ServiceRegistrationInfo info) + { + if (ephemeralSet.TryGetValue(service, out var ephemeral)) + { + return ephemeral; + } + + var newCopy = info.CloneUninitialized(); + + ephemeralSet.Add(service, newCopy); + + return newCopy; + } + private ServiceRegistrationInfo GetInitializedServiceInfo(Service service) { var createdEphemeralSet = false; @@ -407,35 +433,9 @@ private void BeginServiceInfoInitialization(Service service, ServiceRegistration info.BeginInitialization(registrationSources); } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static IEnumerable ExcludeSource(IEnumerable sources, IRegistrationSource exclude) - { - foreach (var item in sources) - { - if (item != exclude) - { - yield return item; - } - } - } - [MethodImpl(MethodImplOptions.AggressiveInlining)] private ServiceRegistrationInfo GetServiceInfo(Service service) { return _serviceInfo.GetOrAdd(service, RegInfoFactory); } - - private static ServiceRegistrationInfo GetEphemeralServiceInfo(Dictionary ephemeralSet, Service service, ServiceRegistrationInfo info) - { - if (ephemeralSet.TryGetValue(service, out var ephemeral)) - { - return ephemeral; - } - - var newCopy = info.CloneUninitialized(); - - ephemeralSet.Add(service, newCopy); - - return newCopy; - } } diff --git a/src/Autofac/Core/ResolvedParameter.cs b/src/Autofac/Core/ResolvedParameter.cs index c2f5c17ad..188cdc86d 100644 --- a/src/Autofac/Core/ResolvedParameter.cs +++ b/src/Autofac/Core/ResolvedParameter.cs @@ -26,34 +26,24 @@ public ResolvedParameter(Func predicate, } /// - /// Returns true if the parameter is able to provide a value to a particular site. + /// Construct a that will match parameters of type + /// and resolve for those parameters an implementation + /// registered with the key . /// - /// Constructor, method, or property-mutator parameter. - /// The component context in which the value is being provided. - /// If the result is true, the valueProvider parameter will - /// be set to a function that will lazily retrieve the parameter value. If the result is false, - /// will be set to null. - /// True if a value can be supplied; otherwise, false. - public override bool CanSupplyValue(ParameterInfo pi, IComponentContext context, [NotNullWhen(returnValue: true)] out Func? valueProvider) + /// The type of the parameter to match. + /// The key of the matching service to resolve. + /// A configured instance. + public static ResolvedParameter ForKeyed(object serviceKey) { - if (pi == null) - { - throw new ArgumentNullException(nameof(pi)); - } - - if (context == null) - { - throw new ArgumentNullException(nameof(context)); - } - - if (_predicate(pi, context)) + if (serviceKey == null) { - valueProvider = () => _valueAccessor(pi, context); - return true; + throw new ArgumentNullException(nameof(serviceKey)); } - valueProvider = null; - return false; + var ks = new KeyedService(serviceKey, typeof(TService)); + return new ResolvedParameter( + (pi, c) => pi.ParameterType == typeof(TService) && c.IsRegisteredService(ks), + (pi, c) => c.ResolveService(ks)); } /// @@ -75,23 +65,33 @@ public static ResolvedParameter ForNamed(string serviceName) } /// - /// Construct a that will match parameters of type - /// and resolve for those parameters an implementation - /// registered with the key . + /// Returns true if the parameter is able to provide a value to a particular site. /// - /// The type of the parameter to match. - /// The key of the matching service to resolve. - /// A configured instance. - public static ResolvedParameter ForKeyed(object serviceKey) + /// Constructor, method, or property-mutator parameter. + /// The component context in which the value is being provided. + /// If the result is true, the valueProvider parameter will + /// be set to a function that will lazily retrieve the parameter value. If the result is false, + /// will be set to null. + /// True if a value can be supplied; otherwise, false. + public override bool CanSupplyValue(ParameterInfo pi, IComponentContext context, [NotNullWhen(returnValue: true)] out Func? valueProvider) { - if (serviceKey == null) + if (pi == null) { - throw new ArgumentNullException(nameof(serviceKey)); + throw new ArgumentNullException(nameof(pi)); } - var ks = new KeyedService(serviceKey, typeof(TService)); - return new ResolvedParameter( - (pi, c) => pi.ParameterType == typeof(TService) && c.IsRegisteredService(ks), - (pi, c) => c.ResolveService(ks)); + if (context == null) + { + throw new ArgumentNullException(nameof(context)); + } + + if (_predicate(pi, context)) + { + valueProvider = () => _valueAccessor(pi, context); + return true; + } + + valueProvider = null; + return false; } } diff --git a/src/Autofac/Core/Resolving/BaseGenericResolveDelegateInvoker.cs b/src/Autofac/Core/Resolving/BaseGenericResolveDelegateInvoker.cs index 88b2cbf9a..d3942d284 100644 --- a/src/Autofac/Core/Resolving/BaseGenericResolveDelegateInvoker.cs +++ b/src/Autofac/Core/Resolving/BaseGenericResolveDelegateInvoker.cs @@ -16,6 +16,30 @@ internal abstract class BaseGenericResolveDelegateInvoker { private ParameterInfo[]? _methodParameters; + /// + /// Checks whether there are any parameters in the set of parameters. + /// + /// The list of parameters to check. + /// if there are any parameters; otherwise, . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + protected static bool AnyParameters(IEnumerable parameters) + { + // The by-far most common way you'll end up with no parameters is by + // invoking a Resolve() function call that doesn't accept parameters, so + // the readonly NoParameters shared value is used. + // A ReferenceEquals comparison here handles that neatly, and is + // significantly faster in benchmarks than doing the Any() call in every + // case. + if (ReferenceEquals(parameters, ResolveRequest.NoParameters)) + { + return false; + } + + // Might be some parameters, so use Any to check for parameters. + // For a List- or Array-backed call, this is pretty quick. + return parameters.Any(); + } + /// /// Method implemented by the derived generated class to get the array for the owned delegate. /// @@ -50,28 +74,4 @@ internal abstract class BaseGenericResolveDelegateInvoker return context.Resolve(); } - - /// - /// Checks whether there are any parameters in the set of parameters. - /// - /// The list of parameters to check. - /// if there are any parameters; otherwise, . - [MethodImpl(MethodImplOptions.AggressiveInlining)] - protected static bool AnyParameters(IEnumerable parameters) - { - // The by-far most common way you'll end up with no parameters is by - // invoking a Resolve() function call that doesn't accept parameters, so - // the readonly NoParameters shared value is used. - // A ReferenceEquals comparison here handles that neatly, and is - // significantly faster in benchmarks than doing the Any() call in every - // case. - if (ReferenceEquals(parameters, ResolveRequest.NoParameters)) - { - return false; - } - - // Might be some parameters, so use Any to check for parameters. - // For a List- or Array-backed call, this is pretty quick. - return parameters.Any(); - } } diff --git a/src/Autofac/Core/Resolving/Pipeline/ResolvePipelineBuilder.cs b/src/Autofac/Core/Resolving/Pipeline/ResolvePipelineBuilder.cs index 67474ced0..1f31ead32 100644 --- a/src/Autofac/Core/Resolving/Pipeline/ResolvePipelineBuilder.cs +++ b/src/Autofac/Core/Resolving/Pipeline/ResolvePipelineBuilder.cs @@ -317,6 +317,15 @@ IEnumerator IEnumerable.GetEnumerator() return GetEnumerator(); } + private static string DescribeValidEnumRange(PipelinePhase start, PipelinePhase end) + { + var enumValues = Enum.GetValues(typeof(PipelinePhase)) + .Cast() + .Where(value => value >= start && value <= end); + + return string.Join(", ", enumValues); + } + private void VerifyPhase(PipelinePhase middlewarePhase) { if (Type == PipelineType.Service) @@ -341,13 +350,4 @@ private void VerifyPhase(PipelinePhase middlewarePhase) DescribeValidEnumRange(PipelinePhase.RegistrationPipelineStart, PipelinePhase.Activation))); } } - - private static string DescribeValidEnumRange(PipelinePhase start, PipelinePhase end) - { - var enumValues = Enum.GetValues(typeof(PipelinePhase)) - .Cast() - .Where(value => value >= start && value <= end); - - return string.Join(", ", enumValues); - } } diff --git a/src/Autofac/Diagnostics/DefaultDiagnosticTracer.cs b/src/Autofac/Diagnostics/DefaultDiagnosticTracer.cs index efb0bdd15..b08552cdc 100644 --- a/src/Autofac/Diagnostics/DefaultDiagnosticTracer.cs +++ b/src/Autofac/Diagnostics/DefaultDiagnosticTracer.cs @@ -26,10 +26,10 @@ public class DefaultDiagnosticTracer : OperationDiagnosticTracerBase { private const string RequestExceptionTraced = "__RequestException"; - private readonly ConcurrentDictionary _operationBuilders = new(); - private static readonly string[] NewLineSplit = new[] { Environment.NewLine }; + private readonly ConcurrentDictionary _operationBuilders = new(); + /// /// Initializes a new instance of the class. /// diff --git a/src/Autofac/Features/GeneratedFactories/FactoryGenerator.cs b/src/Autofac/Features/GeneratedFactories/FactoryGenerator.cs index 1177b796c..f4b652e13 100644 --- a/src/Autofac/Features/GeneratedFactories/FactoryGenerator.cs +++ b/src/Autofac/Features/GeneratedFactories/FactoryGenerator.cs @@ -15,13 +15,13 @@ namespace Autofac.Features.GeneratedFactories; /// public class FactoryGenerator { - private readonly Func, Delegate> _generator; - // The explicit '!' default is ok because the code is never executed, it's just used by // the expression tree. private static readonly ConstructorInfo RequestConstructor = ReflectionExtensions.GetConstructor(() => new ResolveRequest(default!, default!, default!, default)); + private readonly Func, Delegate> _generator; + /// /// Initializes a new instance of the class. /// From 5c3734a5a046c42da9aad06ba1fc98656a7f2930 Mon Sep 17 00:00:00 2001 From: Travis Illig Date: Thu, 18 Sep 2025 11:17:36 -0700 Subject: [PATCH 10/15] Enabled member type ordering. --- build/Source.ruleset | 2 - src/Autofac/Builder/RegistrationData.cs | 96 +++++++------- src/Autofac/Core/ActivatingEventArgs.cs | 10 +- .../ProvidedInstanceActivator.cs | 14 +- .../Activators/Reflection/BoundConstructor.cs | 54 ++++---- .../Core/ComponentRegisteredEventArgs.cs | 22 ++-- src/Autofac/Core/ConstantParameter.cs | 10 +- src/Autofac/Core/Container.cs | 96 +++++++------- src/Autofac/Core/IActivatingEventArgs.cs | 10 +- src/Autofac/Core/IComponentRegistration.cs | 22 ++-- src/Autofac/Core/IInstanceActivator.cs | 10 +- src/Autofac/Core/IRegistrationSource.cs | 12 +- .../Core/ImplicitRegistrationSource.cs | 21 +-- src/Autofac/Core/InternalReflectionCaches.cs | 46 +++---- src/Autofac/Core/Lifetime/LifetimeScope.cs | 124 +++++++++--------- src/Autofac/Core/NamedPropertyParameter.cs | 10 +- src/Autofac/Core/ReflectionCacheSet.cs | 32 ++--- .../Registration/ComponentRegistration.cs | 38 +++--- .../ComponentRegistrationLifetimeDecorator.cs | 14 +- .../Registration/ComponentRegistryBuilder.cs | 104 +++++++-------- .../Registration/ExternalRegistrySource.cs | 14 +- .../Registration/IComponentRegistryBuilder.cs | 28 ++-- .../IRegisteredServicesTracker.cs | 50 +++---- .../Registration/ServiceRegistrationInfo.cs | 88 ++++++------- .../IDependencyTrackingResolveOperation.cs | 14 +- .../Core/Resolving/IResolveOperation.cs | 20 +-- .../ActivatorErrorHandlingMiddleware.cs | 8 +- .../CircularDependencyDetectorMiddleware.cs | 10 +- .../Middleware/DisposalTrackingMiddleware.cs | 10 +- .../RegistrationPipelineInvokeMiddleware.cs | 8 +- .../Middleware/ScopeSelectionMiddleware.cs | 10 +- .../Middleware/StartableMiddleware.cs | 8 +- .../Pipeline/DefaultResolveRequestContext.cs | 6 +- .../Pipeline/IResolvePipelineBuilder.cs | 14 +- .../Pipeline/ResolveRequestContext.cs | 16 +-- .../Core/Resolving/ResolveOperation.cs | 34 ++--- src/Autofac/Core/Resolving/SegmentedStack.cs | 10 +- src/Autofac/Core/Service.cs | 22 ++-- src/Autofac/Core/ServiceRegistration.cs | 20 +-- .../OperationDiagnosticTracerBase.cs | 24 ++-- .../CollectionRegistrationSource.cs | 6 +- .../Features/Decorators/DecoratorContext.cs | 32 ++--- .../Features/Decorators/DecoratorService.cs | 16 +-- .../GeneratedFactoryRegistrationSource.cs | 6 +- .../LazyWithMetadataRegistrationSource.cs | 6 +- .../LightweightAdapterRegistrationSource.cs | 6 +- .../StronglyTypedMetaRegistrationSource.cs | 6 +- .../OpenGenericDecoratorRegistrationSource.cs | 6 +- .../OpenGenericDelegateRegistrationSource.cs | 6 +- .../OpenGenericRegistrationSource.cs | 6 +- .../OwnedInstanceRegistrationSource.cs | 6 +- ...yConcreteTypeNotAlreadyRegisteredSource.cs | 30 ++--- .../ContravariantRegistrationSource.cs | 12 +- src/Autofac/ILifetimeScope.cs | 62 ++++----- src/Autofac/Module.cs | 42 +++--- src/Autofac/NamedParameter.cs | 10 +- src/Autofac/PositionalParameter.cs | 10 +- src/Autofac/ResolveRequest.cs | 16 +-- src/Autofac/TypedParameter.cs | 12 +- src/Autofac/Util/Disposable.cs | 24 ++-- 60 files changed, 740 insertions(+), 741 deletions(-) diff --git a/build/Source.ruleset b/build/Source.ruleset index 48f55bce4..0c0a729dc 100644 --- a/build/Source.ruleset +++ b/build/Source.ruleset @@ -26,8 +26,6 @@ - - diff --git a/src/Autofac/Builder/RegistrationData.cs b/src/Autofac/Builder/RegistrationData.cs index 3617323ea..3dcd3c3fe 100644 --- a/src/Autofac/Builder/RegistrationData.cs +++ b/src/Autofac/Builder/RegistrationData.cs @@ -29,11 +29,16 @@ public RegistrationData(Service defaultService) _defaultService = defaultService ?? throw new ArgumentNullException(nameof(defaultService)); Metadata = new Dictionary - { - { MetadataKeys.RegistrationOrderMetadataKey, SequenceGenerator.GetNextUniqueSequence() }, - }; + { + { MetadataKeys.RegistrationOrderMetadataKey, SequenceGenerator.GetNextUniqueSequence() }, + }; } + /// + /// Gets or sets the instance ownership assigned to the component. + /// + public InstanceOwnership Ownership { get; set; } = InstanceOwnership.OwnedByLifetimeScope; + /// /// Gets the services explicitly assigned to the component. /// @@ -53,6 +58,46 @@ public IEnumerable Services } } + /// + /// Gets or sets the lifetime assigned to the component. + /// + public IComponentLifetime Lifetime + { + get + { + return _lifetime; + } + + set + { + _lifetime = value ?? throw new ArgumentNullException(nameof(value)); + } + } + + /// + /// Gets or sets the sharing mode assigned to the component. + /// + public InstanceSharing Sharing { get; set; } = InstanceSharing.None; + + /// + /// Gets the extended properties assigned to the component. + /// + public IDictionary Metadata { get; } + + /// + /// Gets or sets the options for the registration. + /// + public RegistrationOptions Options { get; set; } + + /// + /// Gets or sets the callback used to register this component. + /// + /// + /// A that contains the delegate + /// used to register this component with an . + /// + public DeferredCallback? DeferredCallback { get; set; } + /// /// Add multiple services for the registration, overriding the default. /// @@ -94,51 +139,6 @@ public void AddService(Service service) _services.Add(service); } - /// - /// Gets or sets the instance ownership assigned to the component. - /// - public InstanceOwnership Ownership { get; set; } = InstanceOwnership.OwnedByLifetimeScope; - - /// - /// Gets or sets the lifetime assigned to the component. - /// - public IComponentLifetime Lifetime - { - get - { - return _lifetime; - } - - set - { - _lifetime = value ?? throw new ArgumentNullException(nameof(value)); - } - } - - /// - /// Gets or sets the sharing mode assigned to the component. - /// - public InstanceSharing Sharing { get; set; } = InstanceSharing.None; - - /// - /// Gets the extended properties assigned to the component. - /// - public IDictionary Metadata { get; } - - /// - /// Gets or sets the options for the registration. - /// - public RegistrationOptions Options { get; set; } - - /// - /// Gets or sets the callback used to register this component. - /// - /// - /// A that contains the delegate - /// used to register this component with an . - /// - public DeferredCallback? DeferredCallback { get; set; } - /// /// Copies the contents of another RegistrationData object into this one. /// diff --git a/src/Autofac/Core/ActivatingEventArgs.cs b/src/Autofac/Core/ActivatingEventArgs.cs index b73aee76c..cab6cf411 100644 --- a/src/Autofac/Core/ActivatingEventArgs.cs +++ b/src/Autofac/Core/ActivatingEventArgs.cs @@ -69,6 +69,11 @@ public T Instance } } + /// + /// Gets the parameters supplied to the activator. + /// + public IEnumerable Parameters { get; } + /// /// The instance can be replaced if needed, e.g. by an interface proxy. /// @@ -77,9 +82,4 @@ public void ReplaceInstance(object instance) { Instance = (T)instance; } - - /// - /// Gets the parameters supplied to the activator. - /// - public IEnumerable Parameters { get; } } diff --git a/src/Autofac/Core/Activators/ProvidedInstance/ProvidedInstanceActivator.cs b/src/Autofac/Core/Activators/ProvidedInstance/ProvidedInstanceActivator.cs index 5c23878bf..f1de67ca1 100644 --- a/src/Autofac/Core/Activators/ProvidedInstance/ProvidedInstanceActivator.cs +++ b/src/Autofac/Core/Activators/ProvidedInstance/ProvidedInstanceActivator.cs @@ -26,6 +26,13 @@ public ProvidedInstanceActivator(object instance) _instance = instance; } + /// + /// Gets or sets a value indicating whether the activator disposes the instance that it holds. + /// Necessary because otherwise instances that are never resolved will never be + /// disposed. + /// + public bool DisposeInstance { get; set; } + /// public void ConfigurePipeline(IComponentRegistryServices componentRegistryServices, IResolvePipelineBuilder pipelineBuilder) { @@ -56,13 +63,6 @@ private object GetInstance() return _instance; } - /// - /// Gets or sets a value indicating whether the activator disposes the instance that it holds. - /// Necessary because otherwise instances that are never resolved will never be - /// disposed. - /// - public bool DisposeInstance { get; set; } - /// protected override void Dispose(bool disposing) { diff --git a/src/Autofac/Core/Activators/Reflection/BoundConstructor.cs b/src/Autofac/Core/Activators/Reflection/BoundConstructor.cs index 4a7b19452..139c296de 100644 --- a/src/Autofac/Core/Activators/Reflection/BoundConstructor.cs +++ b/src/Autofac/Core/Activators/Reflection/BoundConstructor.cs @@ -19,26 +19,6 @@ public class BoundConstructor private readonly Func[]? _valueRetrievers; private readonly ParameterInfo? _firstNonBindableParameter; - /// - /// Initializes a new instance of the class for a successful bind. - /// - /// The binder that generated this binding. - /// The instance factory. - /// The set of value-retrieval functions. - /// A with details about the successful bind. - [SuppressMessage("Design", "CA1062:Validate arguments of public methods", Justification = "Validated in constructor.")] - public static BoundConstructor ForBindSuccess(ConstructorBinder binder, Func factory, Func[] valueRetrievers) - => new(binder, factory, valueRetrievers); - - /// - /// Initializes a new instance of the class, for an unsuccessful bind. - /// - /// The binder that generated this binding. - /// The first parameter that prevented binding. - /// A with details about the unsuccessful bind. - public static BoundConstructor ForBindFailure(ConstructorBinder binder, ParameterInfo firstNonBindableParameter) => - new(binder, firstNonBindableParameter); - /// /// Initializes a new instance of the class for a successful bind. /// @@ -95,6 +75,33 @@ internal BoundConstructor(ConstructorBinder binder, ParameterInfo firstNonBindab /// public bool CanInstantiate { get; } + /// + /// Gets a description of the constructor parameter binding. + /// + public string Description => CanInstantiate + ? string.Format(CultureInfo.CurrentCulture, BoundConstructorResources.BoundConstructor, TargetConstructor) + : string.Format(CultureInfo.CurrentCulture, BoundConstructorResources.NonBindableConstructor, TargetConstructor, _firstNonBindableParameter); + + /// + /// Initializes a new instance of the class for a successful bind. + /// + /// The binder that generated this binding. + /// The instance factory. + /// The set of value-retrieval functions. + /// A with details about the successful bind. + [SuppressMessage("Design", "CA1062:Validate arguments of public methods", Justification = "Validated in constructor.")] + public static BoundConstructor ForBindSuccess(ConstructorBinder binder, Func factory, Func[] valueRetrievers) + => new(binder, factory, valueRetrievers); + + /// + /// Initializes a new instance of the class, for an unsuccessful bind. + /// + /// The binder that generated this binding. + /// The first parameter that prevented binding. + /// A with details about the unsuccessful bind. + public static BoundConstructor ForBindFailure(ConstructorBinder binder, ParameterInfo firstNonBindableParameter) => + new(binder, firstNonBindableParameter); + /// /// Invoke the constructor with the parameter bindings. /// @@ -135,13 +142,6 @@ public object Instantiate() } } - /// - /// Gets a description of the constructor parameter binding. - /// - public string Description => CanInstantiate - ? string.Format(CultureInfo.CurrentCulture, BoundConstructorResources.BoundConstructor, TargetConstructor) - : string.Format(CultureInfo.CurrentCulture, BoundConstructorResources.NonBindableConstructor, TargetConstructor, _firstNonBindableParameter); - /// Returns a System.String that represents the current System.Object. /// A System.String that represents the current System.Object. public override string ToString() diff --git a/src/Autofac/Core/ComponentRegisteredEventArgs.cs b/src/Autofac/Core/ComponentRegisteredEventArgs.cs index 22aa7f1d7..73a31c05c 100644 --- a/src/Autofac/Core/ComponentRegisteredEventArgs.cs +++ b/src/Autofac/Core/ComponentRegisteredEventArgs.cs @@ -6,21 +6,11 @@ namespace Autofac.Core; /// -/// Information about the ocurrence of a component being registered +/// Information about the occurrence of a component being registered /// with a container. /// public class ComponentRegisteredEventArgs : EventArgs { - /// - /// Gets the into which the registration was made. - /// - public IComponentRegistryBuilder ComponentRegistryBuilder { get; } - - /// - /// Gets the component registration. - /// - public IComponentRegistration ComponentRegistration { get; } - /// /// Initializes a new instance of the class. /// @@ -31,4 +21,14 @@ public ComponentRegisteredEventArgs(IComponentRegistryBuilder registryBuilder, I ComponentRegistryBuilder = registryBuilder ?? throw new ArgumentNullException(nameof(registryBuilder)); ComponentRegistration = componentRegistration ?? throw new ArgumentNullException(nameof(componentRegistration)); } + + /// + /// Gets the into which the registration was made. + /// + public IComponentRegistryBuilder ComponentRegistryBuilder { get; } + + /// + /// Gets the component registration. + /// + public IComponentRegistration ComponentRegistration { get; } } diff --git a/src/Autofac/Core/ConstantParameter.cs b/src/Autofac/Core/ConstantParameter.cs index 9f50a1c82..8cdff9119 100644 --- a/src/Autofac/Core/ConstantParameter.cs +++ b/src/Autofac/Core/ConstantParameter.cs @@ -12,11 +12,6 @@ public abstract class ConstantParameter : Parameter { private readonly Predicate _predicate; - /// - /// Gets the value of the parameter. - /// - public object? Value { get; } - /// /// Initializes a new instance of the class. /// @@ -32,6 +27,11 @@ protected ConstantParameter(object? value, Predicate predicate) _predicate = predicate ?? throw new ArgumentNullException(nameof(predicate)); } + /// + /// Gets the value of the parameter. + /// + public object? Value { get; } + /// /// Returns true if the parameter is able to provide a value to a particular site. /// diff --git a/src/Autofac/Core/Container.cs b/src/Autofac/Core/Container.cs index c5d0edee1..755792dfd 100644 --- a/src/Autofac/Core/Container.cs +++ b/src/Autofac/Core/Container.cs @@ -29,6 +29,54 @@ internal Container(IComponentRegistry componentRegistry) _rootLifetimeScope = new LifetimeScope(ComponentRegistry); } + /// + /// Fired when a new scope based on the current scope is beginning. + /// + public event EventHandler ChildLifetimeScopeBeginning + { + add { _rootLifetimeScope.ChildLifetimeScopeBeginning += value; } + remove { _rootLifetimeScope.ChildLifetimeScopeBeginning -= value; } + } + + /// + /// Fired when this scope is ending. + /// + public event EventHandler CurrentScopeEnding + { + add { _rootLifetimeScope.CurrentScopeEnding += value; } + remove { _rootLifetimeScope.CurrentScopeEnding -= value; } + } + + /// + /// Fired when a resolve operation is beginning in this scope. + /// + public event EventHandler ResolveOperationBeginning + { + add { _rootLifetimeScope.ResolveOperationBeginning += value; } + remove { _rootLifetimeScope.ResolveOperationBeginning -= value; } + } + + /// + /// Gets the disposer associated with this container. Instances can be associated + /// with it manually if required. + /// + public IDisposer Disposer => _rootLifetimeScope.Disposer; + + /// + /// Gets the tag applied to the lifetime scope. + /// + /// The tag applied to this scope and the contexts generated when + /// it resolves component dependencies. + public object Tag => _rootLifetimeScope.Tag; + + /// + /// Gets associated services with the components that provide them. + /// + public IComponentRegistry ComponentRegistry { get; } + + /// + public DiagnosticListener DiagnosticSource => _rootLifetimeScope.DiagnosticSource; + /// /// Begin a new sub-scope. Instances created via the sub-scope /// will be disposed along with it. @@ -91,54 +139,6 @@ public ILifetimeScope BeginLoadContextLifetimeScope(object tag, AssemblyLoadCont } #endif - /// - public DiagnosticListener DiagnosticSource => _rootLifetimeScope.DiagnosticSource; - - /// - /// Gets the disposer associated with this container. Instances can be associated - /// with it manually if required. - /// - public IDisposer Disposer => _rootLifetimeScope.Disposer; - - /// - /// Gets the tag applied to the lifetime scope. - /// - /// The tag applied to this scope and the contexts generated when - /// it resolves component dependencies. - public object Tag => _rootLifetimeScope.Tag; - - /// - /// Fired when a new scope based on the current scope is beginning. - /// - public event EventHandler ChildLifetimeScopeBeginning - { - add { _rootLifetimeScope.ChildLifetimeScopeBeginning += value; } - remove { _rootLifetimeScope.ChildLifetimeScopeBeginning -= value; } - } - - /// - /// Fired when this scope is ending. - /// - public event EventHandler CurrentScopeEnding - { - add { _rootLifetimeScope.CurrentScopeEnding += value; } - remove { _rootLifetimeScope.CurrentScopeEnding -= value; } - } - - /// - /// Fired when a resolve operation is beginning in this scope. - /// - public event EventHandler ResolveOperationBeginning - { - add { _rootLifetimeScope.ResolveOperationBeginning += value; } - remove { _rootLifetimeScope.ResolveOperationBeginning -= value; } - } - - /// - /// Gets associated services with the components that provide them. - /// - public IComponentRegistry ComponentRegistry { get; } - /// public object ResolveComponent(in ResolveRequest request) { diff --git a/src/Autofac/Core/IActivatingEventArgs.cs b/src/Autofac/Core/IActivatingEventArgs.cs index e8a594a58..cfbcd8f7a 100644 --- a/src/Autofac/Core/IActivatingEventArgs.cs +++ b/src/Autofac/Core/IActivatingEventArgs.cs @@ -32,13 +32,13 @@ public interface IActivatingEventArgs T Instance { get; } /// - /// The instance can be replaced if needed, e.g. by an interface proxy. + /// Gets the parameters supplied to the activator. /// - /// The object to use instead of the activated instance. - void ReplaceInstance(object instance); + IEnumerable Parameters { get; } /// - /// Gets the parameters supplied to the activator. + /// The instance can be replaced if needed, e.g. by an interface proxy. /// - IEnumerable Parameters { get; } + /// The object to use instead of the activated instance. + void ReplaceInstance(object instance); } diff --git a/src/Autofac/Core/IComponentRegistration.cs b/src/Autofac/Core/IComponentRegistration.cs index c31aaef22..ee70778d8 100644 --- a/src/Autofac/Core/IComponentRegistration.cs +++ b/src/Autofac/Core/IComponentRegistration.cs @@ -11,6 +11,17 @@ namespace Autofac.Core; /// public interface IComponentRegistration : IDisposable, IAsyncDisposable { + /// + /// Provides an event that will be invoked just before a pipeline is built, and can be used to add additional middleware + /// at that point. + /// + /// + /// Attaching to this event after a component registration + /// has already been built will throw an exception. + /// + [SuppressMessage("CA1003", "CA1003", Justification = "Breaking API change.")] + event EventHandler PipelineBuilding; + /// /// Gets a unique identifier for this component (shared in all sub-contexts.) /// This value also appears in Services. @@ -62,17 +73,6 @@ public interface IComponentRegistration : IDisposable, IAsyncDisposable /// RegistrationOptions Options { get; } - /// - /// Provides an event that will be invoked just before a pipeline is built, and can be used to add additional middleware - /// at that point. - /// - /// - /// Attaching to this event after a component registration - /// has already been built will throw an exception. - /// - [SuppressMessage("CA1003", "CA1003", Justification = "Breaking API change.")] - event EventHandler PipelineBuilding; - /// /// Builds the resolve pipeline. /// diff --git a/src/Autofac/Core/IInstanceActivator.cs b/src/Autofac/Core/IInstanceActivator.cs index 882ea5511..a487d0292 100644 --- a/src/Autofac/Core/IInstanceActivator.cs +++ b/src/Autofac/Core/IInstanceActivator.cs @@ -10,15 +10,15 @@ namespace Autofac.Core; /// public interface IInstanceActivator : IDisposable { + /// + /// Gets the most specific type that the component instances are known to be castable to. + /// + Type LimitType { get; } + /// /// Allows an implementation to add middleware to a registration's resolve pipeline. /// /// Provides access to the set of all available services. /// The registration's pipeline builder. void ConfigurePipeline(IComponentRegistryServices componentRegistryServices, IResolvePipelineBuilder pipelineBuilder); - - /// - /// Gets the most specific type that the component instances are known to be castable to. - /// - Type LimitType { get; } } diff --git a/src/Autofac/Core/IRegistrationSource.cs b/src/Autofac/Core/IRegistrationSource.cs index bfe57a39c..c1d6a72d0 100644 --- a/src/Autofac/Core/IRegistrationSource.cs +++ b/src/Autofac/Core/IRegistrationSource.cs @@ -9,6 +9,12 @@ namespace Autofac.Core; /// public interface IRegistrationSource { + /// + /// Gets a value indicating whether the registrations provided by this source are 1:1 adapters on top + /// of other components (e.g., Meta, Func, or Owned). + /// + bool IsAdapterForIndividualComponents { get; } + /// /// Retrieve registrations for an unregistered service, to be used /// by the container. @@ -24,10 +30,4 @@ public interface IRegistrationSource /// that do not implement . /// IEnumerable RegistrationsFor(Service service, Func> registrationAccessor); - - /// - /// Gets a value indicating whether the registrations provided by this source are 1:1 adapters on top - /// of other components (e.g., Meta, Func, or Owned). - /// - bool IsAdapterForIndividualComponents { get; } } diff --git a/src/Autofac/Core/ImplicitRegistrationSource.cs b/src/Autofac/Core/ImplicitRegistrationSource.cs index 3af9730fb..f676c1b81 100644 --- a/src/Autofac/Core/ImplicitRegistrationSource.cs +++ b/src/Autofac/Core/ImplicitRegistrationSource.cs @@ -14,11 +14,10 @@ namespace Autofac.Core; /// public abstract class ImplicitRegistrationSource : IRegistrationSource { - private delegate IComponentRegistration RegistrationCreator(Service providedService, Service valueService, ServiceRegistration valueRegistration); - private static readonly MethodInfo CreateRegistrationMethod = typeof(ImplicitRegistrationSource).GetDeclaredMethod(nameof(CreateRegistration)); private readonly Type _type; + private readonly string _cacheKey; /// @@ -41,6 +40,16 @@ protected ImplicitRegistrationSource(Type type) } } + private delegate IComponentRegistration RegistrationCreator(Service providedService, Service valueService, ServiceRegistration valueRegistration); + + /// + public virtual bool IsAdapterForIndividualComponents => true; + + /// + /// Gets the description of the registration source. + /// + public virtual string Description => GetType().Name; + /// public IEnumerable RegistrationsFor(Service service, Func> registrationAccessor) { @@ -68,14 +77,6 @@ public IEnumerable RegistrationsFor(Service service, Fun .Select(v => registrationCreator(service, valueService, v)); } - /// - public virtual bool IsAdapterForIndividualComponents => true; - - /// - /// Gets the description of the registration source. - /// - public virtual string Description => GetType().Name; - /// public override string ToString() => Description; diff --git a/src/Autofac/Core/InternalReflectionCaches.cs b/src/Autofac/Core/InternalReflectionCaches.cs index be5d6becb..003487112 100644 --- a/src/Autofac/Core/InternalReflectionCaches.cs +++ b/src/Autofac/Core/InternalReflectionCaches.cs @@ -14,6 +14,29 @@ namespace Autofac.Core; /// internal class InternalReflectionCaches { + /// + /// Initializes a new instance of the class. + /// + /// The cache set used to retrieve the required caches. + public InternalReflectionCaches(ReflectionCacheSet set) + { + AssemblyScanAllowedTypes = set.GetOrCreateCache(nameof(AssemblyScanAllowedTypes), _ => new ReflectionCacheAssemblyDictionary> + { + Usage = ReflectionCacheUsage.Registration, + }); + + IsGenericEnumerableInterface = set.GetOrCreateCache>(nameof(IsGenericEnumerableInterface)); + IsGenericListOrCollectionInterfaceType = set.GetOrCreateCache>(nameof(IsGenericListOrCollectionInterfaceType)); + IsGenericTypeDefinedBy = set.GetOrCreateCache>(nameof(IsGenericTypeDefinedBy)); + IsGenericTypeContainingType = set.GetOrCreateCache>(nameof(IsGenericTypeContainingType)); + ConstructorBinderFactory = set.GetOrCreateCache>>(nameof(ConstructorBinderFactory)); + AutowiringPropertySetters = set.GetOrCreateCache>>(nameof(AutowiringPropertySetters)); + AutowiringInjectableProperties = set.GetOrCreateCache>>(nameof(AutowiringInjectableProperties)); + DefaultPublicConstructors = set.GetOrCreateCache>(nameof(DefaultPublicConstructors)); + GenericTypeDefinitionByType = set.GetOrCreateCache>(nameof(GenericTypeDefinitionByType)); + HasRequiredMemberAttribute = set.GetOrCreateCache>(nameof(HasRequiredMemberAttribute)); + } + /// /// Gets the cache used by . /// @@ -68,27 +91,4 @@ internal class InternalReflectionCaches /// Gets a cache used by . /// public ReflectionCacheDictionary HasRequiredMemberAttribute { get; } - - /// - /// Initializes a new instance of the class. - /// - /// The cache set used to retrieve the required caches. - public InternalReflectionCaches(ReflectionCacheSet set) - { - AssemblyScanAllowedTypes = set.GetOrCreateCache(nameof(AssemblyScanAllowedTypes), _ => new ReflectionCacheAssemblyDictionary> - { - Usage = ReflectionCacheUsage.Registration, - }); - - IsGenericEnumerableInterface = set.GetOrCreateCache>(nameof(IsGenericEnumerableInterface)); - IsGenericListOrCollectionInterfaceType = set.GetOrCreateCache>(nameof(IsGenericListOrCollectionInterfaceType)); - IsGenericTypeDefinedBy = set.GetOrCreateCache>(nameof(IsGenericTypeDefinedBy)); - IsGenericTypeContainingType = set.GetOrCreateCache>(nameof(IsGenericTypeContainingType)); - ConstructorBinderFactory = set.GetOrCreateCache>>(nameof(ConstructorBinderFactory)); - AutowiringPropertySetters = set.GetOrCreateCache>>(nameof(AutowiringPropertySetters)); - AutowiringInjectableProperties = set.GetOrCreateCache>>(nameof(AutowiringInjectableProperties)); - DefaultPublicConstructors = set.GetOrCreateCache>(nameof(DefaultPublicConstructors)); - GenericTypeDefinitionByType = set.GetOrCreateCache>(nameof(GenericTypeDefinitionByType)); - HasRequiredMemberAttribute = set.GetOrCreateCache>(nameof(HasRequiredMemberAttribute)); - } } diff --git a/src/Autofac/Core/Lifetime/LifetimeScope.cs b/src/Autofac/Core/Lifetime/LifetimeScope.cs index 303690daf..ce02f4122 100644 --- a/src/Autofac/Core/Lifetime/LifetimeScope.cs +++ b/src/Autofac/Core/Lifetime/LifetimeScope.cs @@ -23,6 +23,11 @@ namespace Autofac.Core.Lifetime; [SuppressMessage("Microsoft.ApiDesignGuidelines", "CA2213", Justification = "The creator of the parent lifetime scope is responsible for disposal.")] public class LifetimeScope : Disposable, ISharingLifetimeScope, IServiceProvider { + /// + /// The tag applied to root scopes when no other tag is specified. + /// + public static readonly object RootTag = "root"; + /// /// Protects shared instances from concurrent access. Other members and the base class are thread-safe. /// @@ -32,19 +37,6 @@ public class LifetimeScope : Disposable, ISharingLifetimeScope, IServiceProvider private object? _anonymousTag; private LifetimeScope? _parentScope; - /// - /// Gets the id of the lifetime scope self-registration. - /// - internal static Guid SelfRegistrationId { get; } = Guid.NewGuid(); - - /// - /// The tag applied to root scopes when no other tag is specified. - /// - public static readonly object RootTag = "root"; - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private object MakeAnonymousTag() => _anonymousTag = new object(); - /// /// Initializes a new instance of the class. /// @@ -87,6 +79,60 @@ public LifetimeScope(IComponentRegistry componentRegistry) { } + /// + /// Fired when a new scope based on the current scope is beginning. + /// + public event EventHandler? ChildLifetimeScopeBeginning; + + /// + /// Fired when this scope is ending. + /// + public event EventHandler? CurrentScopeEnding; + + /// + /// Fired when a resolve operation is beginning in this scope. + /// + public event EventHandler? ResolveOperationBeginning; + + /// + /// Gets the id of the lifetime scope self-registration. + /// + internal static Guid SelfRegistrationId { get; } = Guid.NewGuid(); + + /// + /// Gets the parent of this node of the hierarchy, or null. + /// + public ISharingLifetimeScope? ParentLifetimeScope => _parentScope; + + /// + /// Gets the root of the sharing hierarchy. + /// + public ISharingLifetimeScope RootLifetimeScope { get; } + + /// + /// Gets the to which + /// trace events should be written. + /// + internal DiagnosticListener DiagnosticSource { get; } + + /// + /// Gets the disposer associated with this container. Instances can be associated + /// with it manually if required. + /// + public IDisposer Disposer { get; } = new Disposer(); + + /// + /// Gets the tag applied to the lifetime scope. + /// + /// The tag applied to this scope and the contexts generated when + /// it resolves component dependencies. + public object Tag { get; } + + /// + /// Gets the services associated with the components that provide them. + /// + public IComponentRegistry ComponentRegistry { get; } + /// /// Begin a new anonymous sub-scope. Instances created via the sub-scope /// will be disposed along with it. @@ -113,6 +159,9 @@ public ILifetimeScope BeginLifetimeScope(object tag) return scope; } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private object MakeAnonymousTag() => _anonymousTag = new object(); + private void CheckTagIsUnique(object tag) { if (ReferenceEquals(tag, _anonymousTag)) @@ -142,12 +191,6 @@ private void RaiseBeginning(ILifetimeScope scope) handler?.Invoke(this, new LifetimeScopeBeginningEventArgs(scope)); } - /// - /// Gets the to which - /// trace events should be written. - /// - internal DiagnosticListener DiagnosticSource { get; } - /// /// Begin a new anonymous sub-scope, with additional components available to it. /// Component instances created via the new scope @@ -333,16 +376,6 @@ public object ResolveComponent(in ResolveRequest request) return operation.Execute(request); } - /// - /// Gets the parent of this node of the hierarchy, or null. - /// - public ISharingLifetimeScope? ParentLifetimeScope => _parentScope; - - /// - /// Gets the root of the sharing hierarchy. - /// - public ISharingLifetimeScope RootLifetimeScope { get; } - /// public object CreateSharedInstance(Guid id, Func creator) { @@ -421,24 +454,6 @@ public bool TryGetSharedInstance(Guid primaryId, Guid? qualifyingId, [NotNullWhe : _sharedQualifiedInstances.TryGetValue((primaryId, qualifyingId.Value), out value); } - /// - /// Gets the disposer associated with this container. Instances can be associated - /// with it manually if required. - /// - public IDisposer Disposer { get; } = new Disposer(); - - /// - /// Gets the tag applied to the lifetime scope. - /// - /// The tag applied to this scope and the contexts generated when - /// it resolves component dependencies. - public object Tag { get; } - - /// - /// Gets the services associated with the components that provide them. - /// - public IComponentRegistry ComponentRegistry { get; } - /// /// Releases unmanaged and - optionally - managed resources. /// @@ -529,21 +544,6 @@ private bool IsTreeDisposed() return this.ResolveOptional(serviceType); } - /// - /// Fired when a new scope based on the current scope is beginning. - /// - public event EventHandler? ChildLifetimeScopeBeginning; - - /// - /// Fired when this scope is ending. - /// - public event EventHandler? CurrentScopeEnding; - - /// - /// Fired when a resolve operation is beginning in this scope. - /// - public event EventHandler? ResolveOperationBeginning; - [DoesNotReturn] private static void ThrowDisposedException() { diff --git a/src/Autofac/Core/NamedPropertyParameter.cs b/src/Autofac/Core/NamedPropertyParameter.cs index 1723fad32..96d9b24b1 100644 --- a/src/Autofac/Core/NamedPropertyParameter.cs +++ b/src/Autofac/Core/NamedPropertyParameter.cs @@ -12,11 +12,6 @@ namespace Autofac.Core; /// public class NamedPropertyParameter : ConstantParameter { - /// - /// Gets the name of the property. - /// - public string Name { get; private set; } - /// /// Initializes a new instance of the class. /// @@ -31,4 +26,9 @@ public NamedPropertyParameter(string name, object? value) { Name = Enforce.ArgumentNotNullOrEmpty(name, "name"); } + + /// + /// Gets the name of the property. + /// + public string Name { get; private set; } } diff --git a/src/Autofac/Core/ReflectionCacheSet.cs b/src/Autofac/Core/ReflectionCacheSet.cs index d88abf428..49d7b131e 100644 --- a/src/Autofac/Core/ReflectionCacheSet.cs +++ b/src/Autofac/Core/ReflectionCacheSet.cs @@ -19,6 +19,14 @@ public sealed class ReflectionCacheSet private readonly ConcurrentDictionary _caches = new(); + /// + /// Initializes a new instance of the class. + /// + public ReflectionCacheSet() + { + Internal = new InternalReflectionCaches(this); + } + /// /// Gets the shared . /// @@ -48,14 +56,6 @@ public static ReflectionCacheSet Shared } } - /// - /// Initializes a new instance of the class. - /// - public ReflectionCacheSet() - { - Internal = new InternalReflectionCaches(this); - } - /// /// Gets the instance of the known Internal caches defined in . /// @@ -102,12 +102,6 @@ public TCacheStore GetOrCreateCache(string cacheName, Func - where TCacheStore : IReflectionCache, new() - { - public static Func Factory { get; } = static (k) => new TCacheStore(); - } - /// /// Clear the internal reflection cache. Only call this method if you are /// dynamically unloading types from the process; calling this method @@ -149,14 +143,14 @@ public void Clear(ReflectionCacheClearPredicate predicate) } /// - /// Invoked when the container is built, to allow the cache to apply clearing behaviour. + /// Invoked when the container is built, to allow the cache to apply clearing behavior. /// /// True if we should clear caches marked only for registration. internal void OnContainerBuildClearCaches(bool clearRegistrationCaches) { if (clearRegistrationCaches) { - // Default behaviour on container build is to clear any caches marked + // Default behavior on container build is to clear any caches marked // as only being used during registration. foreach (var cache in GetAllCaches()) { @@ -187,4 +181,10 @@ private IEnumerable GetAllCaches() yield return externalItem.Value; } } + + private static class CacheFactory + where TCacheStore : IReflectionCache, new() + { + public static Func Factory { get; } = static (k) => new TCacheStore(); + } } diff --git a/src/Autofac/Core/Registration/ComponentRegistration.cs b/src/Autofac/Core/Registration/ComponentRegistration.cs index e4029abe0..465cc546c 100644 --- a/src/Autofac/Core/Registration/ComponentRegistration.cs +++ b/src/Autofac/Core/Registration/ComponentRegistration.cs @@ -150,6 +150,25 @@ public ComponentRegistration( Options = options | (_target.Options & OptionsCopiedFromTargetRegistration); } + /// + public event EventHandler? PipelineBuilding + { + add + { + if (_builtComponentPipeline is object) + { + throw new InvalidOperationException(ComponentRegistrationResources.PipelineAlreadyBuilt); + } + + _pipelineBuildEvent += value; + } + + remove + { + _pipelineBuildEvent -= value; + } + } + /// /// Gets the component registration upon which this registration is based. /// If this registration was created directly by the user, returns this. @@ -197,25 +216,6 @@ public ComponentRegistration( /// public RegistrationOptions Options { get; } - /// - public event EventHandler? PipelineBuilding - { - add - { - if (_builtComponentPipeline is object) - { - throw new InvalidOperationException(ComponentRegistrationResources.PipelineAlreadyBuilt); - } - - _pipelineBuildEvent += value; - } - - remove - { - _pipelineBuildEvent -= value; - } - } - /// public IResolvePipeline ResolvePipeline { diff --git a/src/Autofac/Core/Registration/ComponentRegistrationLifetimeDecorator.cs b/src/Autofac/Core/Registration/ComponentRegistrationLifetimeDecorator.cs index ba06530f1..5ea54a7ff 100644 --- a/src/Autofac/Core/Registration/ComponentRegistrationLifetimeDecorator.cs +++ b/src/Autofac/Core/Registration/ComponentRegistrationLifetimeDecorator.cs @@ -25,6 +25,13 @@ public ComponentRegistrationLifetimeDecorator(IComponentRegistration inner, ICom Lifetime = lifetime ?? throw new ArgumentNullException(nameof(lifetime)); } + /// + public event EventHandler PipelineBuilding + { + add => _inner.PipelineBuilding += value; + remove => _inner.PipelineBuilding -= value; + } + /// public Guid Id => _inner.Id; @@ -55,13 +62,6 @@ public ComponentRegistrationLifetimeDecorator(IComponentRegistration inner, ICom /// public RegistrationOptions Options => _inner.Options; - /// - public event EventHandler PipelineBuilding - { - add => _inner.PipelineBuilding += value; - remove => _inner.PipelineBuilding -= value; - } - /// public void BuildResolvePipeline(IComponentRegistryServices registryServices) { diff --git a/src/Autofac/Core/Registration/ComponentRegistryBuilder.cs b/src/Autofac/Core/Registration/ComponentRegistryBuilder.cs index 96c79d6e3..047691a19 100644 --- a/src/Autofac/Core/Registration/ComponentRegistryBuilder.cs +++ b/src/Autofac/Core/Registration/ComponentRegistryBuilder.cs @@ -31,6 +31,58 @@ internal ComponentRegistryBuilder(IRegisteredServicesTracker registeredServicesT _registeredServicesTracker.RegistrationSourceAdded += OnRegistrationSourceAdded; } + /// + /// Fired whenever a component is registered - either explicitly or via a + /// . + /// + public event EventHandler Registered + { + add + { + foreach (IComponentRegistration registration in _registeredServicesTracker.Registrations) + { + value(this, new ComponentRegisteredEventArgs(this, registration)); + } + + Properties[MetadataKeys.RegisteredPropertyKey] = GetRegistered() + value; + } + + remove + { + Properties[MetadataKeys.RegisteredPropertyKey] = GetRegistered() - value; + } + } + + /// + /// Fired when an is added to the registry. + /// + public event EventHandler RegistrationSourceAdded + { + add + { + foreach (IRegistrationSource source in _registeredServicesTracker.Sources) + { + value(this, new RegistrationSourceAddedEventArgs(this, source)); + } + + Properties[MetadataKeys.RegistrationSourceAddedPropertyKey] = GetRegistrationSourceAdded() + value; + } + + remove + { + Properties[MetadataKeys.RegistrationSourceAddedPropertyKey] = GetRegistrationSourceAdded() - value; + } + } + + /// + /// Gets the set of properties used during component registration. + /// + /// + /// An that can be used to share + /// context across registrations. + /// + public IDictionary Properties { get; } + private void OnRegistered(object? sender, IComponentRegistration e) { var handler = GetRegistered(); @@ -65,15 +117,6 @@ protected override ValueTask DisposeAsync(bool disposing) return _registeredServicesTracker.DisposeAsync(); } - /// - /// Gets the set of properties used during component registration. - /// - /// - /// An that can be used to share - /// context across registrations. - /// - public IDictionary Properties { get; } - /// /// Create a new with all the component registrations that have been made. /// @@ -150,28 +193,6 @@ public void Register(IComponentRegistration registration, bool preserveDefaults) _registeredServicesTracker.AddRegistration(registration, preserveDefaults); } - /// - /// Fired whenever a component is registered - either explicitly or via a - /// . - /// - public event EventHandler Registered - { - add - { - foreach (IComponentRegistration registration in _registeredServicesTracker.Registrations) - { - value(this, new ComponentRegisteredEventArgs(this, registration)); - } - - Properties[MetadataKeys.RegisteredPropertyKey] = GetRegistered() + value; - } - - remove - { - Properties[MetadataKeys.RegisteredPropertyKey] = GetRegistered() - value; - } - } - /// /// Add a registration source that will provide registrations on-the-fly. /// @@ -185,27 +206,6 @@ public void AddRegistrationSource(IRegistrationSource source) public void AddServiceMiddlewareSource(IServiceMiddlewareSource servicePipelineSource) => _registeredServicesTracker.AddServiceMiddlewareSource(servicePipelineSource); - /// - /// Fired when an is added to the registry. - /// - public event EventHandler RegistrationSourceAdded - { - add - { - foreach (IRegistrationSource source in _registeredServicesTracker.Sources) - { - value(this, new RegistrationSourceAddedEventArgs(this, source)); - } - - Properties[MetadataKeys.RegistrationSourceAddedPropertyKey] = GetRegistrationSourceAdded() + value; - } - - remove - { - Properties[MetadataKeys.RegistrationSourceAddedPropertyKey] = GetRegistrationSourceAdded() - value; - } - } - [MethodImpl(MethodImplOptions.AggressiveInlining)] private EventHandler? GetRegistered() { diff --git a/src/Autofac/Core/Registration/ExternalRegistrySource.cs b/src/Autofac/Core/Registration/ExternalRegistrySource.cs index ef5034759..2be8a16a5 100644 --- a/src/Autofac/Core/Registration/ExternalRegistrySource.cs +++ b/src/Autofac/Core/Registration/ExternalRegistrySource.cs @@ -29,6 +29,13 @@ public ExternalRegistrySource(IComponentRegistry registry, bool isolatedScope) _isolatedScope = isolatedScope; } + /// + /// Gets a value indicating whether components are adapted from the same logical scope. + /// In this case because the components that are adapted do not come from the same + /// logical scope, we must return false to avoid duplicating them. + /// + public bool IsAdapterForIndividualComponents => false; + /// /// Retrieve registrations for an unregistered service, to be used /// by the container. @@ -61,11 +68,4 @@ public IEnumerable RegistrationsFor(Service service, Fun } } } - - /// - /// Gets a value indicating whether components are adapted from the same logical scope. - /// In this case because the components that are adapted do not come from the same - /// logical scope, we must return false to avoid duplicating them. - /// - public bool IsAdapterForIndividualComponents => false; } diff --git a/src/Autofac/Core/Registration/IComponentRegistryBuilder.cs b/src/Autofac/Core/Registration/IComponentRegistryBuilder.cs index db5dfdc6e..dd00462f1 100644 --- a/src/Autofac/Core/Registration/IComponentRegistryBuilder.cs +++ b/src/Autofac/Core/Registration/IComponentRegistryBuilder.cs @@ -11,10 +11,15 @@ namespace Autofac.Core.Registration; public interface IComponentRegistryBuilder : IDisposable, IAsyncDisposable { /// - /// Create a new with all the component registrations that have been made. + /// Fired whenever a component is registered - either explicitly or via a + /// . /// - /// A new component registry with the configured component registrations. - IComponentRegistry Build(); + event EventHandler Registered; + + /// + /// Fired when an is added to the registry. + /// + event EventHandler RegistrationSourceAdded; /// /// Gets the set of properties used during component registration. @@ -25,6 +30,12 @@ public interface IComponentRegistryBuilder : IDisposable, IAsyncDisposable /// IDictionary Properties { get; } + /// + /// Create a new with all the component registrations that have been made. + /// + /// A new component registry with the configured component registrations. + IComponentRegistry Build(); + /// /// Register a component. /// @@ -39,12 +50,6 @@ public interface IComponentRegistryBuilder : IDisposable, IAsyncDisposable /// component will not be changed. void Register(IComponentRegistration registration, bool preserveDefaults); - /// - /// Fired whenever a component is registered - either explicitly or via a - /// . - /// - event EventHandler Registered; - /// /// Determines whether the specified service is registered. /// @@ -71,9 +76,4 @@ public interface IComponentRegistryBuilder : IDisposable, IAsyncDisposable /// The middleware to register. /// The mode of insertion into the pipeline. void RegisterServiceMiddleware(Service service, IResolveMiddleware middleware, MiddlewareInsertionMode insertionMode = MiddlewareInsertionMode.EndOfPhase); - - /// - /// Fired when an is added to the registry. - /// - event EventHandler RegistrationSourceAdded; } diff --git a/src/Autofac/Core/Registration/IRegisteredServicesTracker.cs b/src/Autofac/Core/Registration/IRegisteredServicesTracker.cs index b90785e17..f33c7bc10 100644 --- a/src/Autofac/Core/Registration/IRegisteredServicesTracker.cs +++ b/src/Autofac/Core/Registration/IRegisteredServicesTracker.cs @@ -10,6 +10,31 @@ namespace Autofac.Core.Registration; /// internal interface IRegisteredServicesTracker : IDisposable, IAsyncDisposable, IComponentRegistryServices { + /// + /// Fired whenever a component is registered - either explicitly or via an . + /// + event EventHandler Registered; + + /// + /// Fired when an is added to the registry. + /// + event EventHandler RegistrationSourceAdded; + + /// + /// Gets the registered components. + /// + IEnumerable Registrations { get; } + + /// + /// Gets the registration sources that are used by the registry. + /// + IEnumerable Sources { get; } + + /// + /// Gets the set of registered service middleware sources. + /// + IEnumerable ServiceMiddlewareSources { get; } + /// /// Adds a registration to the list of registered services. /// @@ -38,37 +63,12 @@ internal interface IRegisteredServicesTracker : IDisposable, IAsyncDisposable, I /// The source to register. void AddServiceMiddlewareSource(IServiceMiddlewareSource serviceMiddlewareSource); - /// - /// Fired whenever a component is registered - either explicitly or via an . - /// - event EventHandler Registered; - - /// - /// Fired when an is added to the registry. - /// - event EventHandler RegistrationSourceAdded; - /// /// Should be called prior to the construction of a to /// indicate that the tracker is complete, and requested service information should no longer be ephemeral. /// void Complete(); - /// - /// Gets the registered components. - /// - IEnumerable Registrations { get; } - - /// - /// Gets the registration sources that are used by the registry. - /// - IEnumerable Sources { get; } - - /// - /// Gets the set of registered service middleware sources. - /// - IEnumerable ServiceMiddlewareSources { get; } - /// /// Gets the set of configured service middleware for a service. /// diff --git a/src/Autofac/Core/Registration/ServiceRegistrationInfo.cs b/src/Autofac/Core/Registration/ServiceRegistrationInfo.cs index ac4d93515..c010ec80c 100644 --- a/src/Autofac/Core/Registration/ServiceRegistrationInfo.cs +++ b/src/Autofac/Core/Registration/ServiceRegistrationInfo.cs @@ -113,34 +113,6 @@ public IEnumerable Implementations /// public IResolvePipeline ServicePipeline => _resolvePipeline ?? throw new InvalidOperationException(ServiceRegistrationInfoResources.NotInitialized); - /// - /// Gets the set of all middleware registered against the service (excluding the default middleware). - /// - public IEnumerable ServiceMiddleware - { - get - { - if (_customPipelineBuilder is null) - { - return Enumerable.Empty(); - } - - return _customPipelineBuilder.Middleware.Where(t => !ServicePipelines.IsDefaultMiddleware(t)); - } - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private void RequiresInitialization() - { - // Implementations can be read by consumers while we are inside an initialization window, - // even when the initialization hasn't finished yet. - // The InitializationDepth property is always 0 outside of the lock-protected initialization block. - if (InitializationDepth == 0 && !IsInitialized) - { - throw new InvalidOperationException(ServiceRegistrationInfoResources.NotInitialized); - } - } - /// /// Gets a value indicating whether any implementations are known. /// @@ -170,6 +142,50 @@ public bool HasCustomServiceMiddleware _sourceImplementations is not null || _preserveDefaultImplementations is not null; + /// + /// Gets the set of all middleware registered against the service (excluding the default middleware). + /// + public IEnumerable ServiceMiddleware + { + get + { + if (_customPipelineBuilder is null) + { + return Enumerable.Empty(); + } + + return _customPipelineBuilder.Middleware.Where(t => !ServicePipelines.IsDefaultMiddleware(t)); + } + } + + /// + /// Gets a value indicating whether this service info is initializing. + /// + public bool IsInitializing => !IsInitialized && _sourcesToQuery is not null; + + /// + /// Gets a value indicating whether there are any sources left to query. + /// + public bool HasSourcesToQuery => IsInitializing && _sourcesToQuery!.Count != 0; + + /// + IEnumerable IResolvePipelineBuilder.Middleware => ServiceMiddleware; + + /// + PipelineType IResolvePipelineBuilder.Type => PipelineType.Service; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void RequiresInitialization() + { + // Implementations can be read by consumers while we are inside an initialization window, + // even when the initialization hasn't finished yet. + // The InitializationDepth property is always 0 outside of the lock-protected initialization block. + if (InitializationDepth == 0 && !IsInitialized) + { + throw new InvalidOperationException(ServiceRegistrationInfoResources.NotInitialized); + } + } + /// /// Add an implementation for the service. /// @@ -255,16 +271,6 @@ public bool TryGetRegistration([NotNullWhen(returnValue: true)] out IComponentRe return registration is not null; } - /// - /// Gets a value indicating whether this service info is initializing. - /// - public bool IsInitializing => !IsInitialized && _sourcesToQuery is not null; - - /// - /// Gets a value indicating whether there are any sources left to query. - /// - public bool HasSourcesToQuery => IsInitializing && _sourcesToQuery!.Count != 0; - /// /// Begin the initialization process for this service info, given the set of dynamic sources. /// @@ -385,12 +391,6 @@ public ServiceRegistrationInfo CloneUninitialized() return copy; } - /// - IEnumerable IResolvePipelineBuilder.Middleware => ServiceMiddleware; - - /// - PipelineType IResolvePipelineBuilder.Type => PipelineType.Service; - /// IResolvePipeline IResolvePipelineBuilder.Build() { diff --git a/src/Autofac/Core/Resolving/IDependencyTrackingResolveOperation.cs b/src/Autofac/Core/Resolving/IDependencyTrackingResolveOperation.cs index 4bc965d29..33588faee 100644 --- a/src/Autofac/Core/Resolving/IDependencyTrackingResolveOperation.cs +++ b/src/Autofac/Core/Resolving/IDependencyTrackingResolveOperation.cs @@ -11,13 +11,6 @@ namespace Autofac.Core.Resolving; /// public interface IDependencyTrackingResolveOperation : IResolveOperation { - /// - /// Enter a new dependency chain block where subsequent requests inside the operation are allowed to repeat - /// registrations from before the block. - /// - /// A disposable that should be disposed to exit the block. - IDisposable EnterNewDependencyDetectionBlock(); - /// /// Gets the modifiable active request stack. /// @@ -27,4 +20,11 @@ public interface IDependencyTrackingResolveOperation : IResolveOperation /// hence it's internal. /// SegmentedStack RequestStack { get; } + + /// + /// Enter a new dependency chain block where subsequent requests inside the operation are allowed to repeat + /// registrations from before the block. + /// + /// A disposable that should be disposed to exit the block. + IDisposable EnterNewDependencyDetectionBlock(); } diff --git a/src/Autofac/Core/Resolving/IResolveOperation.cs b/src/Autofac/Core/Resolving/IResolveOperation.cs index 6472646cb..f65ff8459 100644 --- a/src/Autofac/Core/Resolving/IResolveOperation.cs +++ b/src/Autofac/Core/Resolving/IResolveOperation.cs @@ -12,6 +12,16 @@ namespace Autofac.Core.Resolving; /// public interface IResolveOperation { + /// + /// Raised when a resolve request starts. + /// + event EventHandler? ResolveRequestBeginning; + + /// + /// Raised when the entire operation is complete. + /// + event EventHandler? CurrentOperationEnding; + /// /// Gets the active resolve request. /// @@ -43,16 +53,6 @@ public interface IResolveOperation /// ResolveRequest? InitiatingRequest { get; } - /// - /// Raised when a resolve request starts. - /// - event EventHandler? ResolveRequestBeginning; - - /// - /// Raised when the entire operation is complete. - /// - event EventHandler? CurrentOperationEnding; - /// /// Get or create and share an instance of the requested service in the . /// diff --git a/src/Autofac/Core/Resolving/Middleware/ActivatorErrorHandlingMiddleware.cs b/src/Autofac/Core/Resolving/Middleware/ActivatorErrorHandlingMiddleware.cs index 4cdbac50f..8de645990 100644 --- a/src/Autofac/Core/Resolving/Middleware/ActivatorErrorHandlingMiddleware.cs +++ b/src/Autofac/Core/Resolving/Middleware/ActivatorErrorHandlingMiddleware.cs @@ -13,15 +13,15 @@ internal class ActivatorErrorHandlingMiddleware : IResolveMiddleware { private const string ActivatorChainExceptionData = "ActivatorChain"; + private ActivatorErrorHandlingMiddleware() + { + } + /// /// Gets a singleton instance of the middleware. /// public static ActivatorErrorHandlingMiddleware Instance { get; } = new ActivatorErrorHandlingMiddleware(); - private ActivatorErrorHandlingMiddleware() - { - } - /// public PipelinePhase Phase => PipelinePhase.Activation; diff --git a/src/Autofac/Core/Resolving/Middleware/CircularDependencyDetectorMiddleware.cs b/src/Autofac/Core/Resolving/Middleware/CircularDependencyDetectorMiddleware.cs index 151c2f915..a10cd6b17 100644 --- a/src/Autofac/Core/Resolving/Middleware/CircularDependencyDetectorMiddleware.cs +++ b/src/Autofac/Core/Resolving/Middleware/CircularDependencyDetectorMiddleware.cs @@ -17,11 +17,6 @@ internal class CircularDependencyDetectorMiddleware : IResolveMiddleware /// public const int DefaultMaxResolveDepth = 50; - /// - /// Gets the default instance of . - /// - public static CircularDependencyDetectorMiddleware Default { get; } = new CircularDependencyDetectorMiddleware(DefaultMaxResolveDepth); - private readonly int _maxResolveDepth; /// @@ -33,6 +28,11 @@ public CircularDependencyDetectorMiddleware(int maxResolveDepth) _maxResolveDepth = maxResolveDepth; } + /// + /// Gets the default instance of . + /// + public static CircularDependencyDetectorMiddleware Default { get; } = new CircularDependencyDetectorMiddleware(DefaultMaxResolveDepth); + /// public PipelinePhase Phase => PipelinePhase.ResolveRequestStart; diff --git a/src/Autofac/Core/Resolving/Middleware/DisposalTrackingMiddleware.cs b/src/Autofac/Core/Resolving/Middleware/DisposalTrackingMiddleware.cs index 4befffab2..69b69d02b 100644 --- a/src/Autofac/Core/Resolving/Middleware/DisposalTrackingMiddleware.cs +++ b/src/Autofac/Core/Resolving/Middleware/DisposalTrackingMiddleware.cs @@ -10,16 +10,16 @@ namespace Autofac.Core.Resolving.Middleware; /// internal class DisposalTrackingMiddleware : IResolveMiddleware { - /// - /// Gets the singleton instance of the . - /// - public static DisposalTrackingMiddleware Instance { get; } = new DisposalTrackingMiddleware(); - private DisposalTrackingMiddleware() { // Singleton use only. } + /// + /// Gets the singleton instance of the . + /// + public static DisposalTrackingMiddleware Instance { get; } = new DisposalTrackingMiddleware(); + /// public PipelinePhase Phase => PipelinePhase.Activation; diff --git a/src/Autofac/Core/Resolving/Middleware/RegistrationPipelineInvokeMiddleware.cs b/src/Autofac/Core/Resolving/Middleware/RegistrationPipelineInvokeMiddleware.cs index 00655d3ec..c9a9bd6f0 100644 --- a/src/Autofac/Core/Resolving/Middleware/RegistrationPipelineInvokeMiddleware.cs +++ b/src/Autofac/Core/Resolving/Middleware/RegistrationPipelineInvokeMiddleware.cs @@ -10,15 +10,15 @@ namespace Autofac.Core.Resolving.Middleware; /// internal class RegistrationPipelineInvokeMiddleware : IResolveMiddleware { + private RegistrationPipelineInvokeMiddleware() + { + } + /// /// Gets the singleton instance of this middleware. /// public static RegistrationPipelineInvokeMiddleware Instance { get; } = new RegistrationPipelineInvokeMiddleware(); - private RegistrationPipelineInvokeMiddleware() - { - } - /// public PipelinePhase Phase => PipelinePhase.ServicePipelineEnd; diff --git a/src/Autofac/Core/Resolving/Middleware/ScopeSelectionMiddleware.cs b/src/Autofac/Core/Resolving/Middleware/ScopeSelectionMiddleware.cs index a3ca47466..56e5cb390 100644 --- a/src/Autofac/Core/Resolving/Middleware/ScopeSelectionMiddleware.cs +++ b/src/Autofac/Core/Resolving/Middleware/ScopeSelectionMiddleware.cs @@ -12,16 +12,16 @@ namespace Autofac.Core.Resolving.Middleware; /// internal class ScopeSelectionMiddleware : IResolveMiddleware { - /// - /// Gets the singleton instance of the . - /// - public static ScopeSelectionMiddleware Instance => new(); - private ScopeSelectionMiddleware() { // Only want to use the static instance. } + /// + /// Gets the singleton instance of the . + /// + public static ScopeSelectionMiddleware Instance => new(); + /// public PipelinePhase Phase => PipelinePhase.ScopeSelection; diff --git a/src/Autofac/Core/Resolving/Middleware/StartableMiddleware.cs b/src/Autofac/Core/Resolving/Middleware/StartableMiddleware.cs index 6d4679bd3..20a46c765 100644 --- a/src/Autofac/Core/Resolving/Middleware/StartableMiddleware.cs +++ b/src/Autofac/Core/Resolving/Middleware/StartableMiddleware.cs @@ -11,15 +11,15 @@ namespace Autofac.Core.Resolving.Middleware; /// internal class StartableMiddleware : IResolveMiddleware { + private StartableMiddleware() + { + } + /// /// Gets the singleton instance of the . /// public static StartableMiddleware Instance { get; } = new StartableMiddleware(); - private StartableMiddleware() - { - } - /// public PipelinePhase Phase => PipelinePhase.Activation; diff --git a/src/Autofac/Core/Resolving/Pipeline/DefaultResolveRequestContext.cs b/src/Autofac/Core/Resolving/Pipeline/DefaultResolveRequestContext.cs index 1a6e3195b..8efc3892a 100644 --- a/src/Autofac/Core/Resolving/Pipeline/DefaultResolveRequestContext.cs +++ b/src/Autofac/Core/Resolving/Pipeline/DefaultResolveRequestContext.cs @@ -37,6 +37,9 @@ internal DefaultResolveRequestContext( DiagnosticSource = diagnosticSource; } + /// + public override event EventHandler? RequestCompleting; + /// public override IResolveOperation Operation { get; } @@ -75,9 +78,6 @@ public override object? Instance /// public override IComponentRegistry ComponentRegistry => ActivationScope.ComponentRegistry; - /// - public override event EventHandler? RequestCompleting; - /// public override DecoratorContext? DecoratorContext { get; set; } diff --git a/src/Autofac/Core/Resolving/Pipeline/IResolvePipelineBuilder.cs b/src/Autofac/Core/Resolving/Pipeline/IResolvePipelineBuilder.cs index 8eebd57c6..bc9dabf99 100644 --- a/src/Autofac/Core/Resolving/Pipeline/IResolvePipelineBuilder.cs +++ b/src/Autofac/Core/Resolving/Pipeline/IResolvePipelineBuilder.cs @@ -8,12 +8,6 @@ namespace Autofac.Core.Resolving.Pipeline; /// public interface IResolvePipelineBuilder { - /// - /// Construct a concrete resolve pipeline from this builder. - /// - /// A built pipeline. - IResolvePipeline Build(); - /// /// Gets the set of middleware currently registered. /// @@ -24,6 +18,12 @@ public interface IResolvePipelineBuilder /// PipelineType Type { get; } + /// + /// Construct a concrete resolve pipeline from this builder. + /// + /// A built pipeline. + IResolvePipeline Build(); + /// /// Use a piece of middleware in a resolve pipeline. /// @@ -35,7 +35,7 @@ public interface IResolvePipelineBuilder /// /// Use a set of multiple, ordered middleware instances in a resolve pipeline. /// - /// The set of middleware items to add to the pipelne. The set of middleware must be pre-ordered by phase. + /// The set of middleware items to add to the pipeline. The set of middleware must be pre-ordered by phase. /// The insertion mode specifying whether to add at the start or end of the phase. /// The same builder instance. IResolvePipelineBuilder UseRange(IEnumerable middleware, MiddlewareInsertionMode insertionMode = MiddlewareInsertionMode.EndOfPhase); diff --git a/src/Autofac/Core/Resolving/Pipeline/ResolveRequestContext.cs b/src/Autofac/Core/Resolving/Pipeline/ResolveRequestContext.cs index 7c67bcbaa..1bb18cba7 100644 --- a/src/Autofac/Core/Resolving/Pipeline/ResolveRequestContext.cs +++ b/src/Autofac/Core/Resolving/Pipeline/ResolveRequestContext.cs @@ -9,6 +9,12 @@ namespace Autofac.Core.Resolving.Pipeline; /// public abstract class ResolveRequestContext : IComponentContext { + /// + /// Provides an event that will fire when the current request completes. + /// Requests will only be considered 'complete' when the overall is completing. + /// + public abstract event EventHandler? RequestCompleting; + /// /// Gets a reference to the owning resolve operation (which might encompass multiple nested requests). /// @@ -72,11 +78,8 @@ public abstract class ResolveRequestContext : IComponentContext /// public abstract DecoratorContext? DecoratorContext { get; set; } - /// - /// Provides an event that will fire when the current request completes. - /// Requests will only be considered 'complete' when the overall is completing. - /// - public abstract event EventHandler? RequestCompleting; + /// + public abstract IComponentRegistry ComponentRegistry { get; } /// /// Use this method to change the that is used in this request. Changing this scope will @@ -91,9 +94,6 @@ public abstract class ResolveRequestContext : IComponentContext /// The new set of parameters. public abstract void ChangeParameters(IEnumerable newParameters); - /// - public abstract IComponentRegistry ComponentRegistry { get; } - /// public abstract object ResolveComponent(in ResolveRequest request); } diff --git a/src/Autofac/Core/Resolving/ResolveOperation.cs b/src/Autofac/Core/Resolving/ResolveOperation.cs index 0ec78ea44..0e1a9b673 100644 --- a/src/Autofac/Core/Resolving/ResolveOperation.cs +++ b/src/Autofac/Core/Resolving/ResolveOperation.cs @@ -36,15 +36,11 @@ public ResolveOperation( DiagnosticSource = diagnosticSource ?? throw new ArgumentNullException(nameof(diagnosticSource)); } - /// - /// Execute the complete resolve operation. - /// - /// The resolution context. - /// The resolved instance. - public object Execute(in ResolveRequest request) - { - return ExecuteOperation(request); - } + /// + public event EventHandler? ResolveRequestBeginning; + + /// + public event EventHandler? CurrentOperationEnding; /// /// Gets the active resolve request. @@ -69,17 +65,24 @@ public object Execute(in ResolveRequest request) /// public int RequestDepth { get; private set; } + /// + public SegmentedStack RequestStack { get; } = new SegmentedStack(); + /// /// Gets the that initiated the operation. Other nested requests may have been /// issued as a result of this one. /// public ResolveRequest? InitiatingRequest { get; private set; } - /// - public event EventHandler? ResolveRequestBeginning; - - /// - public event EventHandler? CurrentOperationEnding; + /// + /// Execute the complete resolve operation. + /// + /// The resolution context. + /// The resolved instance. + public object Execute(in ResolveRequest request) + { + return ExecuteOperation(request); + } /// /// Enter a new dependency chain block where subsequent requests inside the operation are allowed to repeat @@ -88,9 +91,6 @@ public object Execute(in ResolveRequest request) /// A disposable that should be disposed to exit the block. public IDisposable EnterNewDependencyDetectionBlock() => RequestStack.EnterSegment(); - /// - public SegmentedStack RequestStack { get; } = new SegmentedStack(); - /// public object GetOrCreateInstance(ISharingLifetimeScope currentOperationScope, in ResolveRequest request) { diff --git a/src/Autofac/Core/Resolving/SegmentedStack.cs b/src/Autofac/Core/Resolving/SegmentedStack.cs index c2f11d209..6f08e9c09 100644 --- a/src/Autofac/Core/Resolving/SegmentedStack.cs +++ b/src/Autofac/Core/Resolving/SegmentedStack.cs @@ -28,6 +28,11 @@ public SegmentedStack() _array = new T[InitialCapacity]; } + /// + /// Gets the count of the items in the active segment. + /// + public int Count => _next - _activeSegmentBase; + /// /// Push an item onto the stack. /// @@ -81,11 +86,6 @@ public T Pop() return item; } - /// - /// Gets the count of the items in the active segment. - /// - public int Count => _next - _activeSegmentBase; - /// /// Enter a new segment. When this method returns will be zero, and the stack will appear empty. /// diff --git a/src/Autofac/Core/Service.cs b/src/Autofac/Core/Service.cs index 67ff8ca03..d9b0ee31e 100644 --- a/src/Autofac/Core/Service.cs +++ b/src/Autofac/Core/Service.cs @@ -14,17 +14,6 @@ public abstract class Service /// The description. public abstract string Description { get; } - /// - /// Returns a that represents the current . - /// - /// - /// A that represents the current . - /// - public override string ToString() - { - return Description; - } - /// /// Implements the operator ==. /// @@ -47,6 +36,17 @@ public override string ToString() return !(left == right); } + /// + /// Returns a that represents the current . + /// + /// + /// A that represents the current . + /// + public override string ToString() + { + return Description; + } + /// /// Determines whether the specified is equal to the current . /// diff --git a/src/Autofac/Core/ServiceRegistration.cs b/src/Autofac/Core/ServiceRegistration.cs index 2a51d0e8e..fcdf84125 100644 --- a/src/Autofac/Core/ServiceRegistration.cs +++ b/src/Autofac/Core/ServiceRegistration.cs @@ -37,6 +37,16 @@ public ServiceRegistration(IResolvePipeline servicePipeline, IComponentRegistrat /// public IDictionary Metadata => Registration.Metadata; + public static bool operator ==(ServiceRegistration left, ServiceRegistration right) + { + return left.Equals(right); + } + + public static bool operator !=(ServiceRegistration left, ServiceRegistration right) + { + return !(left == right); + } + /// /// Gets the registration order value from the registration. /// @@ -65,14 +75,4 @@ public override int GetHashCode() return Pipeline.GetHashCode() ^ Registration.GetHashCode(); } - - public static bool operator ==(ServiceRegistration left, ServiceRegistration right) - { - return left.Equals(right); - } - - public static bool operator !=(ServiceRegistration left, ServiceRegistration right) - { - return !(left == right); - } } diff --git a/src/Autofac/Diagnostics/OperationDiagnosticTracerBase.cs b/src/Autofac/Diagnostics/OperationDiagnosticTracerBase.cs index d2b05c105..b69b58668 100644 --- a/src/Autofac/Diagnostics/OperationDiagnosticTracerBase.cs +++ b/src/Autofac/Diagnostics/OperationDiagnosticTracerBase.cs @@ -47,18 +47,6 @@ protected OperationDiagnosticTracerBase(IEnumerable subscriptions) } } - /// - public override void Enable(string diagnosticName) - { - throw new NotSupportedException(TracerMessages.SubscriptionsDisabled); - } - - /// - public override void Disable(string diagnosticName) - { - throw new NotSupportedException(TracerMessages.SubscriptionsDisabled); - } - /// /// Event raised when a resolve operation completes and trace data is available. /// @@ -74,6 +62,18 @@ public override void Disable(string diagnosticName) /// public abstract int OperationsInProgress { get; } + /// + public override void Enable(string diagnosticName) + { + throw new NotSupportedException(TracerMessages.SubscriptionsDisabled); + } + + /// + public override void Disable(string diagnosticName) + { + throw new NotSupportedException(TracerMessages.SubscriptionsDisabled); + } + /// /// Invokes the event. /// diff --git a/src/Autofac/Features/Collections/CollectionRegistrationSource.cs b/src/Autofac/Features/Collections/CollectionRegistrationSource.cs index 0dc1dd340..de0da9429 100644 --- a/src/Autofac/Features/Collections/CollectionRegistrationSource.cs +++ b/src/Autofac/Features/Collections/CollectionRegistrationSource.cs @@ -43,6 +43,9 @@ namespace Autofac.Features.Collections; /// internal class CollectionRegistrationSource : IRegistrationSource, IPerScopeRegistrationSource { + /// + public bool IsAdapterForIndividualComponents => false; + /// /// Retrieve registrations for an unregistered service, to be used /// by the container. @@ -154,9 +157,6 @@ public IEnumerable RegistrationsFor(Service service, Fun return new IComponentRegistration[] { registration }; } - /// - public bool IsAdapterForIndividualComponents => false; - /// public override string ToString() => CollectionRegistrationSourceResources.CollectionRegistrationSourceDescription; diff --git a/src/Autofac/Features/Decorators/DecoratorContext.cs b/src/Autofac/Features/Decorators/DecoratorContext.cs index 85c82c335..07ce2a65e 100644 --- a/src/Autofac/Features/Decorators/DecoratorContext.cs +++ b/src/Autofac/Features/Decorators/DecoratorContext.cs @@ -12,6 +12,22 @@ public sealed class DecoratorContext : IDecoratorContext { private readonly IComponentContext _componentContext; + private DecoratorContext( + IComponentContext componentContext, + Type implementationType, + Type serviceType, + object currentInstance, + IReadOnlyList? appliedDecoratorTypes = null, + IReadOnlyList? appliedDecorators = null) + { + _componentContext = componentContext; + ImplementationType = implementationType; + ServiceType = serviceType; + CurrentInstance = currentInstance; + AppliedDecoratorTypes = appliedDecoratorTypes ?? Array.Empty(); + AppliedDecorators = appliedDecorators ?? Array.Empty(); + } + /// public Type ImplementationType { get; private set; } @@ -30,22 +46,6 @@ public sealed class DecoratorContext : IDecoratorContext /// public IComponentRegistry ComponentRegistry => _componentContext.ComponentRegistry; - private DecoratorContext( - IComponentContext componentContext, - Type implementationType, - Type serviceType, - object currentInstance, - IReadOnlyList? appliedDecoratorTypes = null, - IReadOnlyList? appliedDecorators = null) - { - _componentContext = componentContext; - ImplementationType = implementationType; - ServiceType = serviceType; - CurrentInstance = currentInstance; - AppliedDecoratorTypes = appliedDecoratorTypes ?? Array.Empty(); - AppliedDecorators = appliedDecorators ?? Array.Empty(); - } - /// /// Create a new . /// diff --git a/src/Autofac/Features/Decorators/DecoratorService.cs b/src/Autofac/Features/Decorators/DecoratorService.cs index 4758a0fb6..8d97205af 100644 --- a/src/Autofac/Features/Decorators/DecoratorService.cs +++ b/src/Autofac/Features/Decorators/DecoratorService.cs @@ -13,14 +13,6 @@ namespace Autofac.Features.Decorators; /// public sealed class DecoratorService : Service, IServiceWithType, IEquatable { - /// - public Type ServiceType { get; } - - /// - /// Gets the condition that must be met for the decorator to be applied. - /// - public Func Condition { get; } - /// /// Initializes a new instance of the class. /// @@ -32,6 +24,14 @@ public DecoratorService(Type serviceType, Func? conditi Condition = condition ?? (context => true); } + /// + public Type ServiceType { get; } + + /// + /// Gets the condition that must be met for the decorator to be applied. + /// + public Func Condition { get; } + /// public override string Description => $"Decorator ({ServiceType.FullName})"; diff --git a/src/Autofac/Features/GeneratedFactories/GeneratedFactoryRegistrationSource.cs b/src/Autofac/Features/GeneratedFactories/GeneratedFactoryRegistrationSource.cs index 9a79beb07..c012d5b9d 100644 --- a/src/Autofac/Features/GeneratedFactories/GeneratedFactoryRegistrationSource.cs +++ b/src/Autofac/Features/GeneratedFactories/GeneratedFactoryRegistrationSource.cs @@ -12,6 +12,9 @@ namespace Autofac.Features.GeneratedFactories; /// internal class GeneratedFactoryRegistrationSource : IRegistrationSource { + /// + public bool IsAdapterForIndividualComponents => true; + /// /// Retrieve registrations for an unregistered service, to be used /// by the container. @@ -54,9 +57,6 @@ public IEnumerable RegistrationsFor(Service service, Fun }); } - /// - public bool IsAdapterForIndividualComponents => true; - /// public override string ToString() { diff --git a/src/Autofac/Features/LazyDependencies/LazyWithMetadataRegistrationSource.cs b/src/Autofac/Features/LazyDependencies/LazyWithMetadataRegistrationSource.cs index 19ae1c71c..e61f0fb98 100644 --- a/src/Autofac/Features/LazyDependencies/LazyWithMetadataRegistrationSource.cs +++ b/src/Autofac/Features/LazyDependencies/LazyWithMetadataRegistrationSource.cs @@ -25,6 +25,9 @@ internal class LazyWithMetadataRegistrationSource : IRegistrationSource private delegate IComponentRegistration RegistrationCreator(Service providedService, Service valueService, ServiceRegistration registrationResolveInfo); + /// + public bool IsAdapterForIndividualComponents => true; + /// public IEnumerable RegistrationsFor(Service service, Func> registrationAccessor) { @@ -63,9 +66,6 @@ public IEnumerable RegistrationsFor(Service service, Fun .Select(v => registrationCreator(service, valueService, v)); } - /// - public bool IsAdapterForIndividualComponents => true; - /// public override string ToString() { diff --git a/src/Autofac/Features/LightweightAdapters/LightweightAdapterRegistrationSource.cs b/src/Autofac/Features/LightweightAdapters/LightweightAdapterRegistrationSource.cs index a6ceecae9..d1019e956 100644 --- a/src/Autofac/Features/LightweightAdapters/LightweightAdapterRegistrationSource.cs +++ b/src/Autofac/Features/LightweightAdapters/LightweightAdapterRegistrationSource.cs @@ -33,6 +33,9 @@ public LightweightAdapterRegistrationSource( } } + /// + public bool IsAdapterForIndividualComponents => true; + /// public IEnumerable RegistrationsFor(Service service, Func> registrationAccessor) { @@ -94,9 +97,6 @@ public IEnumerable RegistrationsFor(Service service, Fun return Enumerable.Empty(); } - /// - public bool IsAdapterForIndividualComponents => true; - /// public override string ToString() { diff --git a/src/Autofac/Features/Metadata/StronglyTypedMetaRegistrationSource.cs b/src/Autofac/Features/Metadata/StronglyTypedMetaRegistrationSource.cs index ebc335c8a..4567bc9e4 100644 --- a/src/Autofac/Features/Metadata/StronglyTypedMetaRegistrationSource.cs +++ b/src/Autofac/Features/Metadata/StronglyTypedMetaRegistrationSource.cs @@ -22,6 +22,9 @@ internal class StronglyTypedMetaRegistrationSource : IRegistrationSource private delegate IComponentRegistration RegistrationCreator(Service providedService, Service valueService, ServiceRegistration valueRegistration); + /// + public bool IsAdapterForIndividualComponents => true; + /// public IEnumerable RegistrationsFor(Service service, Func> registrationAccessor) { @@ -58,9 +61,6 @@ public IEnumerable RegistrationsFor(Service service, Fun .Select(v => registrationCreator.Invoke(service, valueService, v)); } - /// - public bool IsAdapterForIndividualComponents => true; - /// public override string ToString() { diff --git a/src/Autofac/Features/OpenGenerics/OpenGenericDecoratorRegistrationSource.cs b/src/Autofac/Features/OpenGenerics/OpenGenericDecoratorRegistrationSource.cs index 7195926b4..ea07ef71b 100644 --- a/src/Autofac/Features/OpenGenerics/OpenGenericDecoratorRegistrationSource.cs +++ b/src/Autofac/Features/OpenGenerics/OpenGenericDecoratorRegistrationSource.cs @@ -51,6 +51,9 @@ public OpenGenericDecoratorRegistrationSource( _existingPipeline = existingPipelineBuilder; } + /// + public bool IsAdapterForIndividualComponents => true; + /// public IEnumerable RegistrationsFor(Service service, Func> registrationAccessor) { @@ -101,9 +104,6 @@ private static Parameter[] AddDecoratedComponentParameter(Service service, Type return resultArray; } - /// - public bool IsAdapterForIndividualComponents => true; - /// public override string ToString() { diff --git a/src/Autofac/Features/OpenGenerics/OpenGenericDelegateRegistrationSource.cs b/src/Autofac/Features/OpenGenerics/OpenGenericDelegateRegistrationSource.cs index 4cd32cc35..aaeba014e 100644 --- a/src/Autofac/Features/OpenGenerics/OpenGenericDelegateRegistrationSource.cs +++ b/src/Autofac/Features/OpenGenerics/OpenGenericDelegateRegistrationSource.cs @@ -34,6 +34,9 @@ public OpenGenericDelegateRegistrationSource( _activatorData = activatorData ?? throw new ArgumentNullException(nameof(activatorData)); } + /// + public bool IsAdapterForIndividualComponents => false; + /// public IEnumerable RegistrationsFor(Service service, Func> registrationAccessor) { @@ -65,9 +68,6 @@ public IEnumerable RegistrationsFor(Service service, Fun } } - /// - public bool IsAdapterForIndividualComponents => false; - /// public override string ToString() { diff --git a/src/Autofac/Features/OpenGenerics/OpenGenericRegistrationSource.cs b/src/Autofac/Features/OpenGenerics/OpenGenericRegistrationSource.cs index bd0a9426b..6d8422735 100644 --- a/src/Autofac/Features/OpenGenerics/OpenGenericRegistrationSource.cs +++ b/src/Autofac/Features/OpenGenerics/OpenGenericRegistrationSource.cs @@ -46,6 +46,9 @@ public OpenGenericRegistrationSource( _activatorData = activatorData; } + /// + public bool IsAdapterForIndividualComponents => false; + /// public IEnumerable RegistrationsFor(Service service, Func> registrationAccessor) { @@ -77,9 +80,6 @@ public IEnumerable RegistrationsFor(Service service, Fun } } - /// - public bool IsAdapterForIndividualComponents => false; - /// public override string ToString() { diff --git a/src/Autofac/Features/OwnedInstances/OwnedInstanceRegistrationSource.cs b/src/Autofac/Features/OwnedInstances/OwnedInstanceRegistrationSource.cs index 90c6cc01e..c890027e5 100644 --- a/src/Autofac/Features/OwnedInstances/OwnedInstanceRegistrationSource.cs +++ b/src/Autofac/Features/OwnedInstances/OwnedInstanceRegistrationSource.cs @@ -20,6 +20,9 @@ public OwnedInstanceRegistrationSource() { } + /// + public override string Description => OwnedInstanceRegistrationSourceResources.OwnedInstanceRegistrationSourceDescription; + /// protected override object ResolveInstance(IComponentContext ctx, in ResolveRequest request) { @@ -39,7 +42,4 @@ protected override object ResolveInstance(IComponentContext ctx, in ResolveRe /// protected override IRegistrationBuilder BuildRegistration(IRegistrationBuilder registration) => registration.ExternallyOwned(); - - /// - public override string Description => OwnedInstanceRegistrationSourceResources.OwnedInstanceRegistrationSourceDescription; } diff --git a/src/Autofac/Features/ResolveAnything/AnyConcreteTypeNotAlreadyRegisteredSource.cs b/src/Autofac/Features/ResolveAnything/AnyConcreteTypeNotAlreadyRegisteredSource.cs index 988cad1c7..fb093332f 100644 --- a/src/Autofac/Features/ResolveAnything/AnyConcreteTypeNotAlreadyRegisteredSource.cs +++ b/src/Autofac/Features/ResolveAnything/AnyConcreteTypeNotAlreadyRegisteredSource.cs @@ -33,6 +33,21 @@ public AnyConcreteTypeNotAlreadyRegisteredSource(Func predicate) _predicate = predicate ?? throw new ArgumentNullException(nameof(predicate)); } + /// + /// Gets a value indicating whether the registrations provided by this source are 1:1 adapters on top + /// of other components (e.g., Meta, Func, or Owned). + /// + public bool IsAdapterForIndividualComponents => false; + + /// + /// Gets or sets an expression used to configure generated registrations. + /// + /// + /// A that can be used to modify the behavior + /// of registrations that are generated by this source. + /// + public Action>? RegistrationConfiguration { get; set; } + /// /// Retrieve registrations for an unregistered service, to be used /// by the container. @@ -74,21 +89,6 @@ public IEnumerable RegistrationsFor( return new[] { builder.CreateRegistration() }; } - /// - /// Gets a value indicating whether the registrations provided by this source are 1:1 adapters on top - /// of other components (e.g., Meta, Func, or Owned). - /// - public bool IsAdapterForIndividualComponents => false; - - /// - /// Gets or sets an expression used to configure generated registrations. - /// - /// - /// A that can be used to modify the behavior - /// of registrations that are generated by this source. - /// - public Action>? RegistrationConfiguration { get; set; } - /// /// Returns a that represents the current . /// diff --git a/src/Autofac/Features/Variance/ContravariantRegistrationSource.cs b/src/Autofac/Features/Variance/ContravariantRegistrationSource.cs index 0f00c26d8..56eacbf58 100644 --- a/src/Autofac/Features/Variance/ContravariantRegistrationSource.cs +++ b/src/Autofac/Features/Variance/ContravariantRegistrationSource.cs @@ -39,6 +39,12 @@ public class ContravariantRegistrationSource : IRegistrationSource { private const string IsContravariantAdapter = "IsContravariantAdapter"; + /// + /// Gets a value indicating whether the registrations provided by this source are 1:1 adapters on top + /// of other components (e.g., Meta, Func, or Owned). + /// + public bool IsAdapterForIndividualComponents => true; + /// /// Retrieve registrations for an unregistered service, to be used /// by the container. @@ -170,10 +176,4 @@ private static bool IsCompatibleInterfaceType(Type type, out int contravariantPa contravariantParameterIndex = default; return false; } - - /// - /// Gets a value indicating whether the registrations provided by this source are 1:1 adapters on top - /// of other components (e.g., Meta, Func, or Owned). - /// - public bool IsAdapterForIndividualComponents => true; } diff --git a/src/Autofac/ILifetimeScope.cs b/src/Autofac/ILifetimeScope.cs index 974562c5c0..e26fc3a96 100644 --- a/src/Autofac/ILifetimeScope.cs +++ b/src/Autofac/ILifetimeScope.cs @@ -64,6 +64,37 @@ namespace Autofac; /// public interface ILifetimeScope : IComponentContext, IDisposable, IAsyncDisposable { + /// + /// Fired when a new scope based on the current scope is beginning. + /// + event EventHandler ChildLifetimeScopeBeginning; + + /// + /// Fired when this scope is ending. + /// + event EventHandler CurrentScopeEnding; + + /// + /// Fired when a resolve operation is beginning in this scope. + /// + event EventHandler ResolveOperationBeginning; + + /// + /// Gets the disposer associated with this . + /// Component instances can be associated with it manually if required. + /// + /// Typical usage does not require interaction with this member- it + /// is used when extending the container. + IDisposer Disposer { get; } + + /// + /// Gets the tag applied to the . + /// + /// Tags allow a level in the lifetime hierarchy to be identified. + /// In most applications, tags are not necessary. + /// + object Tag { get; } + /// /// Begin a new nested scope. Component instances created via the new scope /// will be disposed along with it. @@ -224,35 +255,4 @@ public interface ILifetimeScope : IComponentContext, IDisposable, IAsyncDisposab /// ILifetimeScope BeginLoadContextLifetimeScope(object tag, AssemblyLoadContext loadContext, Action configurationAction); #endif - - /// - /// Gets the disposer associated with this . - /// Component instances can be associated with it manually if required. - /// - /// Typical usage does not require interaction with this member- it - /// is used when extending the container. - IDisposer Disposer { get; } - - /// - /// Gets the tag applied to the . - /// - /// Tags allow a level in the lifetime hierarchy to be identified. - /// In most applications, tags are not necessary. - /// - object Tag { get; } - - /// - /// Fired when a new scope based on the current scope is beginning. - /// - event EventHandler ChildLifetimeScopeBeginning; - - /// - /// Fired when this scope is ending. - /// - event EventHandler CurrentScopeEnding; - - /// - /// Fired when a resolve operation is beginning in this scope. - /// - event EventHandler ResolveOperationBeginning; } diff --git a/src/Autofac/Module.cs b/src/Autofac/Module.cs index 680be017a..d8f214f5d 100644 --- a/src/Autofac/Module.cs +++ b/src/Autofac/Module.cs @@ -46,6 +46,27 @@ namespace Autofac; /// public abstract class Module : IModule { + /// + /// Gets the assembly in which the concrete module type is located. To avoid bugs whereby deriving from a module will + /// change the target assembly, this property can only be used by modules that inherit directly from + /// . + /// + [SuppressMessage("Design", "CA1065:Do not raise exceptions in unexpected locations", Justification = "Prevent breaking change")] + protected virtual Assembly ThisAssembly + { + get + { + var thisType = GetType(); + var baseType = thisType.BaseType; + if (baseType != typeof(Module)) + { + throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, ModuleResources.ThisAssemblyUnavailable, thisType, baseType)); + } + + return thisType.Assembly; + } + } + /// /// Apply the module to the component registry. /// @@ -125,25 +146,4 @@ private void AttachToSources(IComponentRegistryBuilder componentRegistry) componentRegistry.RegistrationSourceAdded += (sender, e) => AttachToRegistrationSource(e.ComponentRegistry, e.RegistrationSource); } - - /// - /// Gets the assembly in which the concrete module type is located. To avoid bugs whereby deriving from a module will - /// change the target assembly, this property can only be used by modules that inherit directly from - /// . - /// - [SuppressMessage("Design", "CA1065:Do not raise exceptions in unexpected locations", Justification = "Prevent breaking change")] - protected virtual Assembly ThisAssembly - { - get - { - var thisType = GetType(); - var baseType = thisType.BaseType; - if (baseType != typeof(Module)) - { - throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, ModuleResources.ThisAssemblyUnavailable, thisType, baseType)); - } - - return thisType.Assembly; - } - } } diff --git a/src/Autofac/NamedParameter.cs b/src/Autofac/NamedParameter.cs index e8b38eeee..5a75bceef 100644 --- a/src/Autofac/NamedParameter.cs +++ b/src/Autofac/NamedParameter.cs @@ -35,11 +35,6 @@ namespace Autofac; /// public class NamedParameter : ConstantParameter { - /// - /// Gets the name of the parameter. - /// - public string Name { get; } - /// /// Initializes a new instance of the class. /// @@ -48,4 +43,9 @@ public class NamedParameter : ConstantParameter public NamedParameter(string name, object? value) : base(value, pi => pi.Name == name) => Name = Enforce.ArgumentNotNullOrEmpty(name, "name"); + + /// + /// Gets the name of the parameter. + /// + public string Name { get; } } diff --git a/src/Autofac/PositionalParameter.cs b/src/Autofac/PositionalParameter.cs index ce4db4c34..063564943 100644 --- a/src/Autofac/PositionalParameter.cs +++ b/src/Autofac/PositionalParameter.cs @@ -36,11 +36,6 @@ namespace Autofac; /// public class PositionalParameter : ConstantParameter { - /// - /// Gets the zero-based position of the parameter. - /// - public int Position { get; private set; } - /// /// Initializes a new instance of the class. /// @@ -56,4 +51,9 @@ public PositionalParameter(int position, object? value) Position = position; } + + /// + /// Gets the zero-based position of the parameter. + /// + public int Position { get; private set; } } diff --git a/src/Autofac/ResolveRequest.cs b/src/Autofac/ResolveRequest.cs index fce8d16ee..5293e4120 100644 --- a/src/Autofac/ResolveRequest.cs +++ b/src/Autofac/ResolveRequest.cs @@ -57,14 +57,6 @@ public ResolveRequest(Service service, ServiceRegistration serviceRegistration, /// public IComponentRegistration? DecoratorTarget { get; } - /// - public override bool Equals(object? obj) => - obj is ResolveRequest other && Equals(other); - - /// - public bool Equals(ResolveRequest other) => - Service == other.Service && Registration == other.Registration && ResolvePipeline == other.ResolvePipeline && Parameters == other.Parameters && DecoratorTarget == other.DecoratorTarget; - /// /// Implements the operator ==. /// @@ -82,6 +74,14 @@ public bool Equals(ResolveRequest other) => public static bool operator !=(ResolveRequest left, ResolveRequest right) => !(left == right); + /// + public override bool Equals(object? obj) => + obj is ResolveRequest other && Equals(other); + + /// + public bool Equals(ResolveRequest other) => + Service == other.Service && Registration == other.Registration && ResolvePipeline == other.ResolvePipeline && Parameters == other.Parameters && DecoratorTarget == other.DecoratorTarget; + /// public override int GetHashCode() => Service.GetHashCode() ^ Registration.GetHashCode() ^ ResolvePipeline.GetHashCode() ^ Parameters.GetHashCode() ^ (DecoratorTarget?.GetHashCode() ?? 0); diff --git a/src/Autofac/TypedParameter.cs b/src/Autofac/TypedParameter.cs index 4a4376240..815961978 100644 --- a/src/Autofac/TypedParameter.cs +++ b/src/Autofac/TypedParameter.cs @@ -35,12 +35,6 @@ namespace Autofac; /// public class TypedParameter : ConstantParameter { - /// - /// Gets the type against which targets are matched. - /// - [SuppressMessage("Microsoft.Naming", "CA1721:PropertyNamesShouldNotMatchGetMethods", Justification = "Property serves a different purpose than the default get method.")] - public Type Type { get; private set; } - /// /// Initializes a new instance of the class. /// @@ -52,6 +46,12 @@ public TypedParameter(Type type, object? value) Type = type ?? throw new ArgumentNullException(nameof(type)); } + /// + /// Gets the type against which targets are matched. + /// + [SuppressMessage("Microsoft.Naming", "CA1721:PropertyNamesShouldNotMatchGetMethods", Justification = "Property serves a different purpose than the default get method.")] + public Type Type { get; private set; } + /// /// Shortcut for creating /// by using the . diff --git a/src/Autofac/Util/Disposable.cs b/src/Autofac/Util/Disposable.cs index 8d192aaea..234ed1465 100644 --- a/src/Autofac/Util/Disposable.cs +++ b/src/Autofac/Util/Disposable.cs @@ -11,6 +11,18 @@ public class Disposable : IDisposable, IAsyncDisposable private const int DisposedFlag = 1; private int _isDisposed; + /// + /// Gets a value indicating whether the current instance has been disposed. + /// + protected bool IsDisposed + { + get + { + Interlocked.MemoryBarrier(); + return _isDisposed == DisposedFlag; + } + } + /// /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. /// @@ -35,18 +47,6 @@ protected virtual void Dispose(bool disposing) { } - /// - /// Gets a value indicating whether the current instance has been disposed. - /// - protected bool IsDisposed - { - get - { - Interlocked.MemoryBarrier(); - return _isDisposed == DisposedFlag; - } - } - /// [SuppressMessage( "Usage", From c6b30bbe36235edd04bd8f9e049326548f575b70 Mon Sep 17 00:00:00 2001 From: Travis Illig Date: Thu, 18 Sep 2025 11:35:07 -0700 Subject: [PATCH 11/15] Enabled ordering by visibility. --- build/Source.ruleset | 2 - src/Autofac/Builder/RegistrationData.cs | 16 +- .../ProvidedInstanceActivator.cs | 28 +- src/Autofac/Core/Container.cs | 30 +- src/Autofac/Core/Disposer.cs | 48 +-- src/Autofac/Core/Lifetime/LifetimeScope.cs | 338 +++++++++--------- .../Registration/ComponentRegistration.cs | 62 ++-- .../Registration/ComponentRegistryBuilder.cs | 68 ++-- .../Registration/ServiceRegistrationInfo.cs | 86 ++--- .../ActivatorErrorHandlingMiddleware.cs | 6 +- .../Pipeline/ResolvePipelineBuilder.cs | 150 ++++---- src/Autofac/Core/Resolving/SegmentedStack.cs | 18 +- .../Diagnostics/DefaultDiagnosticTracer.cs | 8 +- .../Diagnostics/DiagnosticTracerBase.cs | 110 +++--- .../Features/Decorators/DecoratorContext.cs | 6 +- .../GeneratedFactories/FactoryGenerator.cs | 68 ++-- .../OpenGenericDecoratorRegistrationSource.cs | 22 +- .../OpenGenerics/OpenGenericServiceBinder.cs | 102 +++--- ...enGenericScanningRegistrationExtensions.cs | 40 +-- ...RegistrationExtensions.AssemblyScanning.cs | 28 +- src/Autofac/Util/Disposable.cs | 16 +- 21 files changed, 625 insertions(+), 627 deletions(-) diff --git a/build/Source.ruleset b/build/Source.ruleset index 0c0a729dc..1975e6ce2 100644 --- a/build/Source.ruleset +++ b/build/Source.ruleset @@ -26,8 +26,6 @@ - - diff --git a/src/Autofac/Builder/RegistrationData.cs b/src/Autofac/Builder/RegistrationData.cs index 3dcd3c3fe..a732ee0c5 100644 --- a/src/Autofac/Builder/RegistrationData.cs +++ b/src/Autofac/Builder/RegistrationData.cs @@ -169,14 +169,6 @@ public void CopyFrom(RegistrationData that, bool includeDefaultService) AddAll(Metadata, that.Metadata.Where(m => m.Key != MetadataKeys.RegistrationOrderMetadataKey)); } - private static void AddAll(ICollection to, IEnumerable from) - { - foreach (var item in from) - { - to.Add(item); - } - } - /// /// Empties the configured services. /// @@ -185,4 +177,12 @@ public void ClearServices() _services.Clear(); _defaultServiceOverridden = true; } + + private static void AddAll(ICollection to, IEnumerable from) + { + foreach (var item in from) + { + to.Add(item); + } + } } diff --git a/src/Autofac/Core/Activators/ProvidedInstance/ProvidedInstanceActivator.cs b/src/Autofac/Core/Activators/ProvidedInstance/ProvidedInstanceActivator.cs index f1de67ca1..22796689c 100644 --- a/src/Autofac/Core/Activators/ProvidedInstance/ProvidedInstanceActivator.cs +++ b/src/Autofac/Core/Activators/ProvidedInstance/ProvidedInstanceActivator.cs @@ -49,20 +49,6 @@ public void ConfigurePipeline(IComponentRegistryServices componentRegistryServic }); } - private object GetInstance() - { - CheckNotDisposed(); - - if (_activated) - { - throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, ProvidedInstanceActivatorResources.InstanceAlreadyActivated, _instance.GetType())); - } - - _activated = true; - - return _instance; - } - /// protected override void Dispose(bool disposing) { @@ -131,4 +117,18 @@ private static Type GetType(object instance) return instance.GetType(); } + + private object GetInstance() + { + CheckNotDisposed(); + + if (_activated) + { + throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, ProvidedInstanceActivatorResources.InstanceAlreadyActivated, _instance.GetType())); + } + + _activated = true; + + return _instance; + } } diff --git a/src/Autofac/Core/Container.cs b/src/Autofac/Core/Container.cs index 755792dfd..5d8536aab 100644 --- a/src/Autofac/Core/Container.cs +++ b/src/Autofac/Core/Container.cs @@ -145,6 +145,21 @@ public object ResolveComponent(in ResolveRequest request) return _rootLifetimeScope.ResolveComponent(request); } + /// + /// Gets the service object of the specified type. + /// + /// An object that specifies the type of service object + /// to get. + /// + /// A service object of type .-or- null if there is + /// no service object of type . + /// + public object GetService(Type serviceType) + { + // GetService implementation on LifetimeScope either returns an object, or throws. + return ((IServiceProvider)_rootLifetimeScope).GetService(serviceType)!; + } + /// /// Releases unmanaged and - optionally - managed resources. /// @@ -172,19 +187,4 @@ protected override async ValueTask DisposeAsync(bool disposing) // Do not call the base, otherwise the standard Dispose will fire. } - - /// - /// Gets the service object of the specified type. - /// - /// An object that specifies the type of service object - /// to get. - /// - /// A service object of type .-or- null if there is - /// no service object of type . - /// - public object GetService(Type serviceType) - { - // GetService implementation on LifetimeScope either returns an object, or throws. - return ((IServiceProvider)_rootLifetimeScope).GetService(serviceType)!; - } } diff --git a/src/Autofac/Core/Disposer.cs b/src/Autofac/Core/Disposer.cs index b17e79e9b..8520aa84f 100644 --- a/src/Autofac/Core/Disposer.cs +++ b/src/Autofac/Core/Disposer.cs @@ -21,6 +21,30 @@ internal class Disposer : Disposable, IDisposer /// private Stack _items = new(); + /// + /// Adds an object to the disposer, where that object only implements IAsyncDisposable. When the disposer is + /// disposed, so will the object be. + /// This is not typically recommended, and you should implement IDisposable as well. + /// + /// The instance. + /// + /// If this Disposer is disposed of using a synchronous Dispose call, that call will throw an exception. + /// + public void AddInstanceForAsyncDisposal(IAsyncDisposable instance) + { + AddInternal(instance); + } + + /// + /// Adds an object to the disposer. When the disposer is + /// disposed, so will the object be. + /// + /// The instance. + public void AddInstanceForDisposal(IDisposable instance) + { + AddInternal(instance); + } + /// /// Releases unmanaged and - optionally - managed resources. /// @@ -110,30 +134,6 @@ protected override async ValueTask DisposeAsync(bool disposing) } } - /// - /// Adds an object to the disposer, where that object only implements IAsyncDisposable. When the disposer is - /// disposed, so will the object be. - /// This is not typically recommended, and you should implement IDisposable as well. - /// - /// The instance. - /// - /// If this Disposer is disposed of using a synchronous Dispose call, that call will throw an exception. - /// - public void AddInstanceForAsyncDisposal(IAsyncDisposable instance) - { - AddInternal(instance); - } - - /// - /// Adds an object to the disposer. When the disposer is - /// disposed, so will the object be. - /// - /// The instance. - public void AddInstanceForDisposal(IDisposable instance) - { - AddInternal(instance); - } - private void AddInternal(object instance) { if (instance == null) diff --git a/src/Autofac/Core/Lifetime/LifetimeScope.cs b/src/Autofac/Core/Lifetime/LifetimeScope.cs index ce02f4122..cce522510 100644 --- a/src/Autofac/Core/Lifetime/LifetimeScope.cs +++ b/src/Autofac/Core/Lifetime/LifetimeScope.cs @@ -42,41 +42,41 @@ public class LifetimeScope : Disposable, ISharingLifetimeScope, IServiceProvider /// /// The tag applied to the . /// Components used in the scope. - /// Parent scope. - protected LifetimeScope(IComponentRegistry componentRegistry, LifetimeScope parent, object tag) + public LifetimeScope(IComponentRegistry componentRegistry, object tag) { ComponentRegistry = componentRegistry ?? throw new ArgumentNullException(nameof(componentRegistry)); Tag = tag ?? throw new ArgumentNullException(nameof(tag)); - _parentScope = parent ?? throw new ArgumentNullException(nameof(parent)); _sharedInstances[SelfRegistrationId] = this; - RootLifetimeScope = _parentScope.RootLifetimeScope; - DiagnosticSource = _parentScope.DiagnosticSource; + RootLifetimeScope = this; + DiagnosticSource = new DiagnosticListener("Autofac"); + Disposer.AddInstanceForDisposal(DiagnosticSource); } /// /// Initializes a new instance of the class. /// - /// The tag applied to the . /// Components used in the scope. - public LifetimeScope(IComponentRegistry componentRegistry, object tag) + public LifetimeScope(IComponentRegistry componentRegistry) + : this(componentRegistry, RootTag) { - ComponentRegistry = componentRegistry ?? throw new ArgumentNullException(nameof(componentRegistry)); - Tag = tag ?? throw new ArgumentNullException(nameof(tag)); - - _sharedInstances[SelfRegistrationId] = this; - RootLifetimeScope = this; - DiagnosticSource = new DiagnosticListener("Autofac"); - Disposer.AddInstanceForDisposal(DiagnosticSource); } /// /// Initializes a new instance of the class. /// + /// The tag applied to the . /// Components used in the scope. - public LifetimeScope(IComponentRegistry componentRegistry) - : this(componentRegistry, RootTag) + /// Parent scope. + protected LifetimeScope(IComponentRegistry componentRegistry, LifetimeScope parent, object tag) { + ComponentRegistry = componentRegistry ?? throw new ArgumentNullException(nameof(componentRegistry)); + Tag = tag ?? throw new ArgumentNullException(nameof(tag)); + _parentScope = parent ?? throw new ArgumentNullException(nameof(parent)); + + _sharedInstances[SelfRegistrationId] = this; + RootLifetimeScope = _parentScope.RootLifetimeScope; + DiagnosticSource = _parentScope.DiagnosticSource; } /// @@ -94,11 +94,6 @@ public LifetimeScope(IComponentRegistry componentRegistry) /// public event EventHandler? ResolveOperationBeginning; - /// - /// Gets the id of the lifetime scope self-registration. - /// - internal static Guid SelfRegistrationId { get; } = Guid.NewGuid(); - /// /// Gets the parent of this node of the hierarchy, or null. /// @@ -109,12 +104,6 @@ public LifetimeScope(IComponentRegistry componentRegistry) /// public ISharingLifetimeScope RootLifetimeScope { get; } - /// - /// Gets the to which - /// trace events should be written. - /// - internal DiagnosticListener DiagnosticSource { get; } - /// /// Gets the disposer associated with this container. Instances can be associated /// with it manually if required. @@ -133,6 +122,17 @@ public LifetimeScope(IComponentRegistry componentRegistry) /// public IComponentRegistry ComponentRegistry { get; } + /// + /// Gets the id of the lifetime scope self-registration. + /// + internal static Guid SelfRegistrationId { get; } = Guid.NewGuid(); + + /// + /// Gets the to which + /// trace events should be written. + /// + internal DiagnosticListener DiagnosticSource { get; } + /// /// Begin a new anonymous sub-scope. Instances created via the sub-scope /// will be disposed along with it. @@ -159,38 +159,6 @@ public ILifetimeScope BeginLifetimeScope(object tag) return scope; } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private object MakeAnonymousTag() => _anonymousTag = new object(); - - private void CheckTagIsUnique(object tag) - { - if (ReferenceEquals(tag, _anonymousTag)) - { - return; - } - - ISharingLifetimeScope parentScope = this; - while (parentScope != RootLifetimeScope) - { - // In the scope where we are searching for parents, then the parent scope will not be null. - if (parentScope.Tag.Equals(tag)) - { - throw new InvalidOperationException( - string.Format(CultureInfo.CurrentCulture, LifetimeScopeResources.DuplicateTagDetected, tag)); - } - - // In the scope of searching for tags, the ParentLifetimeScope will always be set. - parentScope = parentScope.ParentLifetimeScope!; - } - } - - [SuppressMessage("CA1030", "CA1030", Justification = "This method raises the event; it's not the event proper.")] - private void RaiseBeginning(ILifetimeScope scope) - { - var handler = ChildLifetimeScopeBeginning; - handler?.Invoke(this, new LifetimeScopeBeginningEventArgs(scope)); - } - /// /// Begin a new anonymous sub-scope, with additional components available to it. /// Component instances created via the new scope @@ -278,93 +246,6 @@ public ILifetimeScope BeginLoadContextLifetimeScope(object tag, AssemblyLoadCont } #endif - private LifetimeScope InternalBeginLifetimeScope(object tag, Action configurationAction, bool isolatedScope) - { - if (configurationAction == null) - { - throw new ArgumentNullException(nameof(configurationAction)); - } - - CheckNotDisposed(); - CheckTagIsUnique(tag); - - var localsBuilder = CreateScopeRestrictedRegistry(tag, configurationAction, isolatedScope); - var scope = new LifetimeScope(localsBuilder.Build(), this, tag); - scope.Disposer.AddInstanceForDisposal(localsBuilder); - - if (localsBuilder.Properties.TryGetValue(MetadataKeys.ContainerBuildOptions, out var options) - && options is not null - && !((ContainerBuildOptions)options).HasFlag(ContainerBuildOptions.IgnoreStartableComponents)) - { - StartableManager.StartStartableComponents(localsBuilder.Properties, scope); - } - - // Run any build callbacks. - BuildCallbackManager.RunBuildCallbacks(scope); - - RaiseBeginning(scope); - - return scope; - } - - /// - /// Creates and setup the registry for a child scope. - /// - /// The tag applied to the . - /// Action on a - /// that adds component registrations visible only in the child scope. - /// - /// Indicates whether the generated registry should be 'isolated'; an isolated registry does not hold on to - /// any type information for retrieved services that do not result in registrations. - /// - /// Registry to use for a child scope. - /// It is the responsibility of the caller to make sure that the registry is properly - /// disposed of. This is generally done by adding the registry to the - /// property of the child scope. - private ComponentRegistryBuilder CreateScopeRestrictedRegistry(object tag, Action configurationAction, bool isolatedScope) - { - var restrictedRootScopeLifetime = new MatchingScopeLifetime(tag); - var tracker = new ScopeRestrictedRegisteredServicesTracker(restrictedRootScopeLifetime); - - var fallbackProperties = new FallbackDictionary(ComponentRegistry.Properties); - - foreach (var source in ComponentRegistry.Sources) - { - if (source.IsAdapterForIndividualComponents || (source is IPerScopeRegistrationSource && isolatedScope)) - { - tracker.AddRegistrationSource(source); - } - } - - // Issue #272: Only the most nested parent registry with HasLocalComponents is registered as an external source - // It provides all non-adapting registrations from itself and from it's parent registries - ISharingLifetimeScope? parent = this; - while (parent is not null) - { - if (parent.ComponentRegistry.HasLocalComponents) - { - var externalSource = new ExternalRegistrySource(parent.ComponentRegistry, isolatedScope); - tracker.AddRegistrationSource(externalSource); - - // Add a source for the service pipeline stages. - var externalServicePipelineSource = new ExternalRegistryServiceMiddlewareSource(parent.ComponentRegistry, isolatedScope); - tracker.AddServiceMiddlewareSource(externalServicePipelineSource); - - break; - } - - parent = parent.ParentLifetimeScope; - } - - var registryBuilder = new ComponentRegistryBuilder(tracker, fallbackProperties); - var builder = new ContainerBuilder(fallbackProperties, registryBuilder); - - configurationAction(builder); - - builder.UpdateRegistry(registryBuilder); - return registryBuilder; - } - /// public object ResolveComponent(in ResolveRequest request) { @@ -454,6 +335,25 @@ public bool TryGetSharedInstance(Guid primaryId, Guid? qualifyingId, [NotNullWhe : _sharedQualifiedInstances.TryGetValue((primaryId, qualifyingId.Value), out value); } + /// + /// Gets the service object of the specified type. + /// + /// An object that specifies the type of service object + /// to get. + /// + /// A service object of type .-or- null if there is + /// no service object of type . + /// + public object? GetService(Type serviceType) + { + if (serviceType == null) + { + throw new ArgumentNullException(nameof(serviceType)); + } + + return this.ResolveOptional(serviceType); + } + /// /// Releases unmanaged and - optionally - managed resources. /// @@ -505,6 +405,73 @@ protected override async ValueTask DisposeAsync(bool disposing) // Don't call the base (which would just call the normal Dispose). } + [DoesNotReturn] + private static void ThrowDisposedException() + { + throw new ObjectDisposedException(LifetimeScopeResources.ScopeIsDisposed, innerException: null); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private object MakeAnonymousTag() => _anonymousTag = new object(); + + private void CheckTagIsUnique(object tag) + { + if (ReferenceEquals(tag, _anonymousTag)) + { + return; + } + + ISharingLifetimeScope parentScope = this; + while (parentScope != RootLifetimeScope) + { + // In the scope where we are searching for parents, then the parent scope will not be null. + if (parentScope.Tag.Equals(tag)) + { + throw new InvalidOperationException( + string.Format(CultureInfo.CurrentCulture, LifetimeScopeResources.DuplicateTagDetected, tag)); + } + + // In the scope of searching for tags, the ParentLifetimeScope will always be set. + parentScope = parentScope.ParentLifetimeScope!; + } + } + + [SuppressMessage("CA1030", "CA1030", Justification = "This method raises the event; it's not the event proper.")] + private void RaiseBeginning(ILifetimeScope scope) + { + var handler = ChildLifetimeScopeBeginning; + handler?.Invoke(this, new LifetimeScopeBeginningEventArgs(scope)); + } + + private LifetimeScope InternalBeginLifetimeScope(object tag, Action configurationAction, bool isolatedScope) + { + if (configurationAction == null) + { + throw new ArgumentNullException(nameof(configurationAction)); + } + + CheckNotDisposed(); + CheckTagIsUnique(tag); + + var localsBuilder = CreateScopeRestrictedRegistry(tag, configurationAction, isolatedScope); + var scope = new LifetimeScope(localsBuilder.Build(), this, tag); + scope.Disposer.AddInstanceForDisposal(localsBuilder); + + if (localsBuilder.Properties.TryGetValue(MetadataKeys.ContainerBuildOptions, out var options) + && options is not null + && !((ContainerBuildOptions)options).HasFlag(ContainerBuildOptions.IgnoreStartableComponents)) + { + StartableManager.StartStartableComponents(localsBuilder.Properties, scope); + } + + // Run any build callbacks. + BuildCallbackManager.RunBuildCallbacks(scope); + + RaiseBeginning(scope); + + return scope; + } + [MethodImpl(MethodImplOptions.AggressiveInlining)] private void CheckNotDisposed() { @@ -516,37 +483,70 @@ private void CheckNotDisposed() } /// - /// Gets a value indicating whether this or any of the parent disposables have been disposed. + /// Creates and setup the registry for a child scope. /// - /// true if this instance of any of the parent instances have been disposed. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private bool IsTreeDisposed() + /// The tag applied to the . + /// Action on a + /// that adds component registrations visible only in the child scope. + /// + /// Indicates whether the generated registry should be 'isolated'; an isolated registry does not hold on to + /// any type information for retrieved services that do not result in registrations. + /// + /// Registry to use for a child scope. + /// It is the responsibility of the caller to make sure that the registry is properly + /// disposed of. This is generally done by adding the registry to the + /// property of the child scope. + private ComponentRegistryBuilder CreateScopeRestrictedRegistry(object tag, Action configurationAction, bool isolatedScope) { - return IsDisposed || (_parentScope?.IsTreeDisposed() ?? false); - } + var restrictedRootScopeLifetime = new MatchingScopeLifetime(tag); + var tracker = new ScopeRestrictedRegisteredServicesTracker(restrictedRootScopeLifetime); - /// - /// Gets the service object of the specified type. - /// - /// An object that specifies the type of service object - /// to get. - /// - /// A service object of type .-or- null if there is - /// no service object of type . - /// - public object? GetService(Type serviceType) - { - if (serviceType == null) + var fallbackProperties = new FallbackDictionary(ComponentRegistry.Properties); + + foreach (var source in ComponentRegistry.Sources) { - throw new ArgumentNullException(nameof(serviceType)); + if (source.IsAdapterForIndividualComponents || (source is IPerScopeRegistrationSource && isolatedScope)) + { + tracker.AddRegistrationSource(source); + } } - return this.ResolveOptional(serviceType); + // Issue #272: Only the most nested parent registry with HasLocalComponents is registered as an external source + // It provides all non-adapting registrations from itself and from it's parent registries + ISharingLifetimeScope? parent = this; + while (parent is not null) + { + if (parent.ComponentRegistry.HasLocalComponents) + { + var externalSource = new ExternalRegistrySource(parent.ComponentRegistry, isolatedScope); + tracker.AddRegistrationSource(externalSource); + + // Add a source for the service pipeline stages. + var externalServicePipelineSource = new ExternalRegistryServiceMiddlewareSource(parent.ComponentRegistry, isolatedScope); + tracker.AddServiceMiddlewareSource(externalServicePipelineSource); + + break; + } + + parent = parent.ParentLifetimeScope; + } + + var registryBuilder = new ComponentRegistryBuilder(tracker, fallbackProperties); + var builder = new ContainerBuilder(fallbackProperties, registryBuilder); + + configurationAction(builder); + + builder.UpdateRegistry(registryBuilder); + return registryBuilder; } - [DoesNotReturn] - private static void ThrowDisposedException() + /// + /// Gets a value indicating whether this or any of the parent disposables have been disposed. + /// + /// true if this instance of any of the parent instances have been disposed. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private bool IsTreeDisposed() { - throw new ObjectDisposedException(LifetimeScopeResources.ScopeIsDisposed, innerException: null); + return IsDisposed || (_parentScope?.IsTreeDisposed() ?? false); } } diff --git a/src/Autofac/Core/Registration/ComponentRegistration.cs b/src/Autofac/Core/Registration/ComponentRegistration.cs index 465cc546c..dfa668a4e 100644 --- a/src/Autofac/Core/Registration/ComponentRegistration.cs +++ b/src/Autofac/Core/Registration/ComponentRegistration.cs @@ -244,6 +244,24 @@ public void BuildResolvePipeline(IComponentRegistryServices registryServices) ResolvePipeline = BuildResolvePipeline(registryServices, _lateBuildPipeline); } + /// + /// Describes the component in a human-readable form. + /// + /// A description of the component. + public override string ToString() + { + // Activator = {0}, Services = [{1}], Lifetime = {2}, Sharing = {3}, Ownership = {4}, Pipeline = {5} + return string.Format( + CultureInfo.CurrentCulture, + ComponentRegistrationResources.ToStringFormat, + Activator, + Services.Select(s => s.Description).JoinWith(", "), + Lifetime, + Sharing, + Ownership, + _builtComponentPipeline is null ? ComponentRegistrationResources.PipelineNotBuilt : _builtComponentPipeline.ToString()); + } + /// /// Populates the resolve pipeline with middleware based on the registration, and builds the pipeline. /// @@ -275,37 +293,6 @@ protected virtual IResolvePipeline BuildResolvePipeline(IComponentRegistryServic return _lateBuildPipeline.Build(); } - private bool HasStartableService() - { - foreach (var service in Services) - { - if ((service is TypedService typed) && typed.ServiceType == typeof(IStartable)) - { - return true; - } - } - - return false; - } - - /// - /// Describes the component in a human-readable form. - /// - /// A description of the component. - public override string ToString() - { - // Activator = {0}, Services = [{1}], Lifetime = {2}, Sharing = {3}, Ownership = {4}, Pipeline = {5} - return string.Format( - CultureInfo.CurrentCulture, - ComponentRegistrationResources.ToStringFormat, - Activator, - Services.Select(s => s.Description).JoinWith(", "), - Lifetime, - Sharing, - Ownership, - _builtComponentPipeline is null ? ComponentRegistrationResources.PipelineNotBuilt : _builtComponentPipeline.ToString()); - } - /// protected override void Dispose(bool disposing) { @@ -344,4 +331,17 @@ protected override ValueTask DisposeAsync(bool disposing) // Do not call the base, otherwise the standard Dispose will fire. } + + private bool HasStartableService() + { + foreach (var service in Services) + { + if ((service is TypedService typed) && typed.ServiceType == typeof(IStartable)) + { + return true; + } + } + + return false; + } } diff --git a/src/Autofac/Core/Registration/ComponentRegistryBuilder.cs b/src/Autofac/Core/Registration/ComponentRegistryBuilder.cs index 047691a19..dd32841c4 100644 --- a/src/Autofac/Core/Registration/ComponentRegistryBuilder.cs +++ b/src/Autofac/Core/Registration/ComponentRegistryBuilder.cs @@ -83,40 +83,6 @@ public event EventHandler RegistrationSourceAd /// public IDictionary Properties { get; } - private void OnRegistered(object? sender, IComponentRegistration e) - { - var handler = GetRegistered(); - - handler?.Invoke(this, new ComponentRegisteredEventArgs(this, e)); - } - - private void OnRegistrationSourceAdded(object? sender, IRegistrationSource e) - { - var handler = GetRegistrationSourceAdded(); - - handler?.Invoke(this, new RegistrationSourceAddedEventArgs(this, e)); - } - - /// - protected override void Dispose(bool disposing) - { - _registeredServicesTracker.Registered -= OnRegistered; - _registeredServicesTracker.RegistrationSourceAdded -= OnRegistrationSourceAdded; - _registeredServicesTracker.Dispose(); - - base.Dispose(disposing); - } - - /// - protected override ValueTask DisposeAsync(bool disposing) - { - _registeredServicesTracker.Registered -= OnRegistered; - _registeredServicesTracker.RegistrationSourceAdded -= OnRegistrationSourceAdded; - - // Do not call the base, otherwise the standard Dispose will fire. - return _registeredServicesTracker.DisposeAsync(); - } - /// /// Create a new with all the component registrations that have been made. /// @@ -206,6 +172,40 @@ public void AddRegistrationSource(IRegistrationSource source) public void AddServiceMiddlewareSource(IServiceMiddlewareSource servicePipelineSource) => _registeredServicesTracker.AddServiceMiddlewareSource(servicePipelineSource); + /// + protected override void Dispose(bool disposing) + { + _registeredServicesTracker.Registered -= OnRegistered; + _registeredServicesTracker.RegistrationSourceAdded -= OnRegistrationSourceAdded; + _registeredServicesTracker.Dispose(); + + base.Dispose(disposing); + } + + /// + protected override ValueTask DisposeAsync(bool disposing) + { + _registeredServicesTracker.Registered -= OnRegistered; + _registeredServicesTracker.RegistrationSourceAdded -= OnRegistrationSourceAdded; + + // Do not call the base, otherwise the standard Dispose will fire. + return _registeredServicesTracker.DisposeAsync(); + } + + private void OnRegistered(object? sender, IComponentRegistration e) + { + var handler = GetRegistered(); + + handler?.Invoke(this, new ComponentRegisteredEventArgs(this, e)); + } + + private void OnRegistrationSourceAdded(object? sender, IRegistrationSource e) + { + var handler = GetRegistrationSourceAdded(); + + handler?.Invoke(this, new RegistrationSourceAddedEventArgs(this, e)); + } + [MethodImpl(MethodImplOptions.AggressiveInlining)] private EventHandler? GetRegistered() { diff --git a/src/Autofac/Core/Registration/ServiceRegistrationInfo.cs b/src/Autofac/Core/Registration/ServiceRegistrationInfo.cs index c010ec80c..1ba12652b 100644 --- a/src/Autofac/Core/Registration/ServiceRegistrationInfo.cs +++ b/src/Autofac/Core/Registration/ServiceRegistrationInfo.cs @@ -137,11 +137,6 @@ public bool HasCustomServiceMiddleware } } - private bool Any => - _defaultImplementations.Count > 0 || - _sourceImplementations is not null || - _preserveDefaultImplementations is not null; - /// /// Gets the set of all middleware registered against the service (excluding the default middleware). /// @@ -174,17 +169,10 @@ public IEnumerable ServiceMiddleware /// PipelineType IResolvePipelineBuilder.Type => PipelineType.Service; - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private void RequiresInitialization() - { - // Implementations can be read by consumers while we are inside an initialization window, - // even when the initialization hasn't finished yet. - // The InitializationDepth property is always 0 outside of the lock-protected initialization block. - if (InitializationDepth == 0 && !IsInitialized) - { - throw new InvalidOperationException(ServiceRegistrationInfoResources.NotInitialized); - } - } + private bool Any => + _defaultImplementations.Count > 0 || + _sourceImplementations is not null || + _preserveDefaultImplementations is not null; /// /// Add an implementation for the service. @@ -297,15 +285,6 @@ public void SkipSource(IRegistrationSource source) _sourcesToQuery = new Queue(_sourcesToQuery!.Where(rs => rs != source)); } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private void EnforceDuringInitialization() - { - if (!IsInitializing) - { - throw new InvalidOperationException(ServiceRegistrationInfoResources.NotDuringInitialization); - } - } - /// /// Dequeue the next registration source. /// @@ -335,24 +314,6 @@ public override string ToString() return _service.ToString(); } - private IResolvePipeline BuildPipeline() - { - // Build the custom service pipeline (if we need to). - if (_customPipelineBuilder is object) - { - // Add the default stages. - _customPipelineBuilder.UseRange(ServicePipelines.DefaultMiddleware); - - // Add the default. - return _customPipelineBuilder.Build(); - } - else - { - // Nothing custom, use an empty pipeline. - return ServicePipelines.DefaultServicePipeline; - } - } - /// /// Creates a copy of an uninitialized , preserving existing registrations and custom middleware. /// @@ -421,4 +382,43 @@ IResolvePipelineBuilder IResolvePipelineBuilder.Clone() return _customPipelineBuilder.Clone(); } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void RequiresInitialization() + { + // Implementations can be read by consumers while we are inside an initialization window, + // even when the initialization hasn't finished yet. + // The InitializationDepth property is always 0 outside of the lock-protected initialization block. + if (InitializationDepth == 0 && !IsInitialized) + { + throw new InvalidOperationException(ServiceRegistrationInfoResources.NotInitialized); + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void EnforceDuringInitialization() + { + if (!IsInitializing) + { + throw new InvalidOperationException(ServiceRegistrationInfoResources.NotDuringInitialization); + } + } + + private IResolvePipeline BuildPipeline() + { + // Build the custom service pipeline (if we need to). + if (_customPipelineBuilder is object) + { + // Add the default stages. + _customPipelineBuilder.UseRange(ServicePipelines.DefaultMiddleware); + + // Add the default. + return _customPipelineBuilder.Build(); + } + else + { + // Nothing custom, use an empty pipeline. + return ServicePipelines.DefaultServicePipeline; + } + } } diff --git a/src/Autofac/Core/Resolving/Middleware/ActivatorErrorHandlingMiddleware.cs b/src/Autofac/Core/Resolving/Middleware/ActivatorErrorHandlingMiddleware.cs index 8de645990..2077e40cc 100644 --- a/src/Autofac/Core/Resolving/Middleware/ActivatorErrorHandlingMiddleware.cs +++ b/src/Autofac/Core/Resolving/Middleware/ActivatorErrorHandlingMiddleware.cs @@ -48,6 +48,9 @@ public void Execute(ResolveRequestContext context, Action } } + /// + public override string ToString() => nameof(ActivatorErrorHandlingMiddleware); + private static DependencyResolutionException PropagateActivationException(IInstanceActivator activator, Exception exception) { var activatorChain = activator.DisplayName(); @@ -64,7 +67,4 @@ private static DependencyResolutionException PropagateActivationException(IInsta result.Data[ActivatorChainExceptionData] = activatorChain; return result; } - - /// - public override string ToString() => nameof(ActivatorErrorHandlingMiddleware); } diff --git a/src/Autofac/Core/Resolving/Pipeline/ResolvePipelineBuilder.cs b/src/Autofac/Core/Resolving/Pipeline/ResolvePipelineBuilder.cs index 1f31ead32..8de32ea66 100644 --- a/src/Autofac/Core/Resolving/Pipeline/ResolvePipelineBuilder.cs +++ b/src/Autofac/Core/Resolving/Pipeline/ResolvePipelineBuilder.cs @@ -165,72 +165,39 @@ public IResolvePipelineBuilder UseRange(IEnumerable stages, return this; } - private void AddStage(IResolveMiddleware stage, MiddlewareInsertionMode insertionLocation) + /// + public IResolvePipeline Build() { - VerifyPhase(stage.Phase); + return BuildPipeline(_last); + } - // Start at the beginning. + /// + public IResolvePipelineBuilder Clone() + { + // To clone a pipeline, we create a new instance, then insert the same stage + // objects in the same order. + var newPipeline = new ResolvePipelineBuilder(Type); var currentStage = _first; - var newStageDecl = new MiddlewareDeclaration(stage); - - if (_first is null) - { - _first = _last = newStageDecl; - return; - } - while (currentStage is not null) { - if (insertionLocation == MiddlewareInsertionMode.StartOfPhase ? currentStage.Middleware.Phase >= stage.Phase : currentStage.Middleware.Phase > stage.Phase) - { - if (currentStage.Previous is not null) - { - // Insert the node. - currentStage.Previous.Next = newStageDecl; - newStageDecl.Next = currentStage; - newStageDecl.Previous = currentStage.Previous; - currentStage.Previous = newStageDecl; - } - else - { - _first.Previous = newStageDecl; - newStageDecl.Next = _first; - _first = newStageDecl; - } - - return; - } - + newPipeline.AppendStage(currentStage.Middleware); currentStage = currentStage.Next; } - // Add at the end. - newStageDecl.Previous = _last; - _last!.Next = newStageDecl; - _last = newStageDecl; + return newPipeline; } - private void AppendStage(IResolveMiddleware stage) + /// + public IEnumerator GetEnumerator() { - var newDecl = new MiddlewareDeclaration(stage); - - if (_last is null) - { - _first = _last = newDecl; - } - else - { - newDecl.Previous = _last; - _last.Next = newDecl; - _last = newDecl; - } + return new PipelineBuilderEnumerator(_first); } - /// - public IResolvePipeline Build() + /// + IEnumerator IEnumerable.GetEnumerator() { - return BuildPipeline(_last); + return GetEnumerator(); } private static ResolvePipeline BuildPipeline(MiddlewareDeclaration? lastDecl) @@ -288,42 +255,75 @@ Action Chain(Action next, IResolve return new ResolvePipeline(currentInvoke); } - /// - public IResolvePipelineBuilder Clone() + private static string DescribeValidEnumRange(PipelinePhase start, PipelinePhase end) { - // To clone a pipeline, we create a new instance, then insert the same stage - // objects in the same order. - var newPipeline = new ResolvePipelineBuilder(Type); + var enumValues = Enum.GetValues(typeof(PipelinePhase)) + .Cast() + .Where(value => value >= start && value <= end); + + return string.Join(", ", enumValues); + } + + private void AddStage(IResolveMiddleware stage, MiddlewareInsertionMode insertionLocation) + { + VerifyPhase(stage.Phase); + + // Start at the beginning. var currentStage = _first; - while (currentStage is not null) + var newStageDecl = new MiddlewareDeclaration(stage); + + if (_first is null) { - newPipeline.AppendStage(currentStage.Middleware); - currentStage = currentStage.Next; + _first = _last = newStageDecl; + return; } - return newPipeline; - } + while (currentStage is not null) + { + if (insertionLocation == MiddlewareInsertionMode.StartOfPhase ? currentStage.Middleware.Phase >= stage.Phase : currentStage.Middleware.Phase > stage.Phase) + { + if (currentStage.Previous is not null) + { + // Insert the node. + currentStage.Previous.Next = newStageDecl; + newStageDecl.Next = currentStage; + newStageDecl.Previous = currentStage.Previous; + currentStage.Previous = newStageDecl; + } + else + { + _first.Previous = newStageDecl; + newStageDecl.Next = _first; + _first = newStageDecl; + } - /// - public IEnumerator GetEnumerator() - { - return new PipelineBuilderEnumerator(_first); - } + return; + } - /// - IEnumerator IEnumerable.GetEnumerator() - { - return GetEnumerator(); + currentStage = currentStage.Next; + } + + // Add at the end. + newStageDecl.Previous = _last; + _last!.Next = newStageDecl; + _last = newStageDecl; } - private static string DescribeValidEnumRange(PipelinePhase start, PipelinePhase end) + private void AppendStage(IResolveMiddleware stage) { - var enumValues = Enum.GetValues(typeof(PipelinePhase)) - .Cast() - .Where(value => value >= start && value <= end); + var newDecl = new MiddlewareDeclaration(stage); - return string.Join(", ", enumValues); + if (_last is null) + { + _first = _last = newDecl; + } + else + { + newDecl.Previous = _last; + _last.Next = newDecl; + _last = newDecl; + } } private void VerifyPhase(PipelinePhase middlewarePhase) diff --git a/src/Autofac/Core/Resolving/SegmentedStack.cs b/src/Autofac/Core/Resolving/SegmentedStack.cs index 6f08e9c09..433a2e660 100644 --- a/src/Autofac/Core/Resolving/SegmentedStack.cs +++ b/src/Autofac/Core/Resolving/SegmentedStack.cs @@ -55,15 +55,6 @@ public void Push(T item) } } - // Do not inline; makes it easier to profile stack resizing. - [MethodImpl(MethodImplOptions.NoInlining)] - private void PushWithResize(T item) - { - Array.Resize(ref _array, 2 * _array.Length); - _array[_next] = item; - _next++; - } - /// /// Pop the item at the top of the stack (and return it). /// @@ -111,6 +102,15 @@ IEnumerator IEnumerable.GetEnumerator() return new Enumerator(this); } + // Do not inline; makes it easier to profile stack resizing. + [MethodImpl(MethodImplOptions.NoInlining)] + private void PushWithResize(T item) + { + Array.Resize(ref _array, 2 * _array.Length); + _array[_next] = item; + _next++; + } + private readonly struct StackSegment : IDisposable { private readonly SegmentedStack _stack; diff --git a/src/Autofac/Diagnostics/DefaultDiagnosticTracer.cs b/src/Autofac/Diagnostics/DefaultDiagnosticTracer.cs index b08552cdc..2f3e9f7bb 100644 --- a/src/Autofac/Diagnostics/DefaultDiagnosticTracer.cs +++ b/src/Autofac/Diagnostics/DefaultDiagnosticTracer.cs @@ -297,14 +297,14 @@ public void AppendLine(string value) _builder.AppendLine(value); } - private void AppendIndent() + public override string ToString() { - _builder.Append(' ', IndentSize * _indentCount); + return _builder.ToString(); } - public override string ToString() + private void AppendIndent() { - return _builder.ToString(); + _builder.Append(' ', IndentSize * _indentCount); } } } diff --git a/src/Autofac/Diagnostics/DiagnosticTracerBase.cs b/src/Autofac/Diagnostics/DiagnosticTracerBase.cs index 5034e137c..075ef8f2f 100644 --- a/src/Autofac/Diagnostics/DiagnosticTracerBase.cs +++ b/src/Autofac/Diagnostics/DiagnosticTracerBase.cs @@ -77,35 +77,6 @@ public virtual void Enable(string diagnosticName) EnableBase(diagnosticName); } - /// - /// Subscribes the observer to a particular named diagnostic event. - /// - /// - /// The name of the event to which the observer should subscribe. Diagnostic - /// names are case-sensitive. - /// - /// - /// - /// Derived classes may override the public method to - /// handle consumer calls to enabling events; constructors needing to call - /// non-virtual methods may directly call this to avoid executing against - /// partially constructed derived classes. - /// - /// - /// - protected void EnableBase(string diagnosticName) - { - if (diagnosticName == null) - { - throw new ArgumentNullException(nameof(diagnosticName)); - } - - if (!_subscriptions.Contains(diagnosticName)) - { - _subscriptions.Add(diagnosticName); - } - } - /// /// Subscribes the observer to all Autofac events. /// @@ -158,32 +129,6 @@ public virtual void Disable(string diagnosticName) DisableBase(diagnosticName); } - /// - /// Unsubscribes the observer from a particular named diagnostic event. - /// - /// - /// The name of the event to which the observer should unsubscribe. Diagnostic - /// names are case-sensitive. - /// - /// - /// - /// Derived classes may override the public method to - /// handle consumer calls to disabling events; constructors needing to call - /// non-virtual methods may directly call this to avoid executing against - /// partially constructed derived classes. - /// - /// - /// - protected void DisableBase(string diagnosticName) - { - if (diagnosticName == null) - { - throw new ArgumentNullException(nameof(diagnosticName)); - } - - _subscriptions.Remove(diagnosticName); - } - /// /// Determines if this observer is enabled for listening to a specific /// named event. @@ -237,6 +182,61 @@ public bool IsEnabled(string diagnosticName) Write(value.Key, value.Value); } + /// + /// Subscribes the observer to a particular named diagnostic event. + /// + /// + /// The name of the event to which the observer should subscribe. Diagnostic + /// names are case-sensitive. + /// + /// + /// + /// Derived classes may override the public method to + /// handle consumer calls to enabling events; constructors needing to call + /// non-virtual methods may directly call this to avoid executing against + /// partially constructed derived classes. + /// + /// + /// + protected void EnableBase(string diagnosticName) + { + if (diagnosticName == null) + { + throw new ArgumentNullException(nameof(diagnosticName)); + } + + if (!_subscriptions.Contains(diagnosticName)) + { + _subscriptions.Add(diagnosticName); + } + } + + /// + /// Unsubscribes the observer from a particular named diagnostic event. + /// + /// + /// The name of the event to which the observer should unsubscribe. Diagnostic + /// names are case-sensitive. + /// + /// + /// + /// Derived classes may override the public method to + /// handle consumer calls to disabling events; constructors needing to call + /// non-virtual methods may directly call this to avoid executing against + /// partially constructed derived classes. + /// + /// + /// + protected void DisableBase(string diagnosticName) + { + if (diagnosticName == null) + { + throw new ArgumentNullException(nameof(diagnosticName)); + } + + _subscriptions.Remove(diagnosticName); + } + /// /// Handles the event raised when middleware encounters an error. /// diff --git a/src/Autofac/Features/Decorators/DecoratorContext.cs b/src/Autofac/Features/Decorators/DecoratorContext.cs index 07ce2a65e..ef4bd68b4 100644 --- a/src/Autofac/Features/Decorators/DecoratorContext.cs +++ b/src/Autofac/Features/Decorators/DecoratorContext.cs @@ -46,6 +46,9 @@ private DecoratorContext( /// public IComponentRegistry ComponentRegistry => _componentContext.ComponentRegistry; + /// + public object ResolveComponent(in ResolveRequest request) => _componentContext.ResolveComponent(request); + /// /// Create a new . /// @@ -76,7 +79,4 @@ internal DecoratorContext UpdateContext(object decoratorInstance) return new DecoratorContext(_componentContext, ImplementationType, ServiceType, decoratorInstance, appliedDecoratorTypes, appliedDecorators); } - - /// - public object ResolveComponent(in ResolveRequest request) => _componentContext.ResolveComponent(request); } diff --git a/src/Autofac/Features/GeneratedFactories/FactoryGenerator.cs b/src/Autofac/Features/GeneratedFactories/FactoryGenerator.cs index f4b652e13..e47446ea3 100644 --- a/src/Autofac/Features/GeneratedFactories/FactoryGenerator.cs +++ b/src/Autofac/Features/GeneratedFactories/FactoryGenerator.cs @@ -95,6 +95,40 @@ public FactoryGenerator(Type delegateType, Service service, ServiceRegistration GetParameterMapping(delegateType, parameterMapping)); } + /// + /// Generates a factory delegate that closes over the provided context. + /// + /// The context in which the factory will be used. + /// Parameters provided to the resolve call for the factory itself. + /// A factory delegate that will work within the context. + public Delegate GenerateFactory(IComponentContext context, IEnumerable parameters) + { + if (context == null) + { + throw new ArgumentNullException(nameof(context)); + } + + if (parameters == null) + { + throw new ArgumentNullException(nameof(parameters)); + } + + return _generator(context.Resolve(), parameters); + } + + /// + /// Generates a factory delegate that closes over the provided context. + /// + /// The type of the delegate to generate. + /// The context in which the factory will be used. + /// Parameters provided to the resolve call for the factory itself. + /// A factory delegate that will work within the context. + public TDelegate GenerateFactory(IComponentContext context, IEnumerable parameters) + where TDelegate : class + { + return (TDelegate)(object)GenerateFactory(context, parameters); + } + private static ParameterMapping GetParameterMapping(Type delegateType, ParameterMapping configuredParameterMapping) { if (configuredParameterMapping == ParameterMapping.Adaptive) @@ -184,38 +218,4 @@ private static Expression[] MapParameters(IEnumerable creat .ToArray(), }; } - - /// - /// Generates a factory delegate that closes over the provided context. - /// - /// The context in which the factory will be used. - /// Parameters provided to the resolve call for the factory itself. - /// A factory delegate that will work within the context. - public Delegate GenerateFactory(IComponentContext context, IEnumerable parameters) - { - if (context == null) - { - throw new ArgumentNullException(nameof(context)); - } - - if (parameters == null) - { - throw new ArgumentNullException(nameof(parameters)); - } - - return _generator(context.Resolve(), parameters); - } - - /// - /// Generates a factory delegate that closes over the provided context. - /// - /// The type of the delegate to generate. - /// The context in which the factory will be used. - /// Parameters provided to the resolve call for the factory itself. - /// A factory delegate that will work within the context. - public TDelegate GenerateFactory(IComponentContext context, IEnumerable parameters) - where TDelegate : class - { - return (TDelegate)(object)GenerateFactory(context, parameters); - } } diff --git a/src/Autofac/Features/OpenGenerics/OpenGenericDecoratorRegistrationSource.cs b/src/Autofac/Features/OpenGenerics/OpenGenericDecoratorRegistrationSource.cs index ea07ef71b..35c561a38 100644 --- a/src/Autofac/Features/OpenGenerics/OpenGenericDecoratorRegistrationSource.cs +++ b/src/Autofac/Features/OpenGenerics/OpenGenericDecoratorRegistrationSource.cs @@ -88,6 +88,17 @@ public IEnumerable RegistrationsFor(Service service, Fun return Enumerable.Empty(); } + /// + public override string ToString() + { + return string.Format( + CultureInfo.CurrentCulture, + OpenGenericDecoratorRegistrationSourceResources.OpenGenericDecoratorRegistrationSourceImplFromTo, + _activatorData.ImplementationType.FullName, + ((Service)_activatorData.FromService).Description, + string.Join(", ", _registrationData.Services.Select(s => s.Description).ToArray())); + } + private static Parameter[] AddDecoratedComponentParameter(Service service, Type decoratedParameterType, ServiceRegistration decoratedComponent, IList configuredParameters) { var parameter = new ResolvedParameter( @@ -103,15 +114,4 @@ private static Parameter[] AddDecoratedComponentParameter(Service service, Type return resultArray; } - - /// - public override string ToString() - { - return string.Format( - CultureInfo.CurrentCulture, - OpenGenericDecoratorRegistrationSourceResources.OpenGenericDecoratorRegistrationSourceImplFromTo, - _activatorData.ImplementationType.FullName, - ((Service)_activatorData.FromService).Description, - string.Join(", ", _registrationData.Services.Select(s => s.Description).ToArray())); - } } diff --git a/src/Autofac/Features/OpenGenerics/OpenGenericServiceBinder.cs b/src/Autofac/Features/OpenGenerics/OpenGenericServiceBinder.cs index 4b05584f8..eb5ba2fdc 100644 --- a/src/Autofac/Features/OpenGenerics/OpenGenericServiceBinder.cs +++ b/src/Autofac/Features/OpenGenerics/OpenGenericServiceBinder.cs @@ -68,8 +68,6 @@ public static bool TryBindOpenGenericTypedService( return false; } - private static Type GetGenericTypeDefinition(Type type) => ReflectionCacheSet.Shared.Internal.GenericTypeDefinitionByType.GetOrAdd(type, static t => t.GetGenericTypeDefinition()); - /// /// Given a closed generic service (that is being requested), creates a regular delegate callback /// and associated services from the open generic delegate and services. @@ -123,6 +121,57 @@ public static bool TryBindOpenGenericDelegateService( return false; } + /// + /// Throws an exception if an open generic implementation type cannot implement the set of specified open services. + /// + /// The open generic implementation type. + /// The set of open generic services. + public static void EnforceBindable(Type implementationType, IEnumerable services) + { + if (implementationType == null) + { + throw new ArgumentNullException(nameof(implementationType)); + } + + if (services == null) + { + throw new ArgumentNullException(nameof(services)); + } + + if (!implementationType.IsGenericTypeDefinition) + { + throw new ArgumentException( + string.Format(CultureInfo.CurrentCulture, OpenGenericServiceBinderResources.ImplementorMustBeOpenGenericTypeDefinition, implementationType)); + } + + foreach (var service in services.OfType()) + { + if (!service.ServiceType.IsGenericTypeDefinition) + { + throw new ArgumentException( + string.Format(CultureInfo.CurrentCulture, OpenGenericServiceBinderResources.ServiceTypeMustBeOpenGenericTypeDefinition, service)); + } + + if (service.ServiceType.IsInterface) + { + if (GetInterfaces(implementationType, service.ServiceType).Length == 0) + { + var message = string.Format(CultureInfo.CurrentCulture, OpenGenericServiceBinderResources.ImplementorDoesntImplementService, implementationType.FullName, service.ServiceType.FullName); + throw new InvalidOperationException(message); + } + } + else + { + if (!Traverse.Across(implementationType, t => t.BaseType!).Any(t => IsCompatibleGenericClassDefinition(t, service.ServiceType))) + { + throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, OpenGenericServiceBinderResources.TypesAreNotConvertible, implementationType, service)); + } + } + } + } + + private static Type GetGenericTypeDefinition(Type type) => ReflectionCacheSet.Shared.Internal.GenericTypeDefinitionByType.GetOrAdd(type, static t => t.GetGenericTypeDefinition()); + private static Type?[] TryMapImplementationGenericArguments(Type implementationType, Type serviceType, Type serviceTypeDefinition, Type[] serviceGenericArguments) { if (serviceTypeDefinition == implementationType) @@ -237,55 +286,6 @@ private static Type[] GetInterfaces(Type implementationType, Type serviceType) = .FirstOrDefault(x => x is not null); } - /// - /// Throws an exception if an open generic implementation type cannot implement the set of specified open services. - /// - /// The open generic implementation type. - /// The set of open generic services. - public static void EnforceBindable(Type implementationType, IEnumerable services) - { - if (implementationType == null) - { - throw new ArgumentNullException(nameof(implementationType)); - } - - if (services == null) - { - throw new ArgumentNullException(nameof(services)); - } - - if (!implementationType.IsGenericTypeDefinition) - { - throw new ArgumentException( - string.Format(CultureInfo.CurrentCulture, OpenGenericServiceBinderResources.ImplementorMustBeOpenGenericTypeDefinition, implementationType)); - } - - foreach (var service in services.OfType()) - { - if (!service.ServiceType.IsGenericTypeDefinition) - { - throw new ArgumentException( - string.Format(CultureInfo.CurrentCulture, OpenGenericServiceBinderResources.ServiceTypeMustBeOpenGenericTypeDefinition, service)); - } - - if (service.ServiceType.IsInterface) - { - if (GetInterfaces(implementationType, service.ServiceType).Length == 0) - { - var message = string.Format(CultureInfo.CurrentCulture, OpenGenericServiceBinderResources.ImplementorDoesntImplementService, implementationType.FullName, service.ServiceType.FullName); - throw new InvalidOperationException(message); - } - } - else - { - if (!Traverse.Across(implementationType, t => t.BaseType!).Any(t => IsCompatibleGenericClassDefinition(t, service.ServiceType))) - { - throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, OpenGenericServiceBinderResources.TypesAreNotConvertible, implementationType, service)); - } - } - } - } - private static bool IsCompatibleGenericClassDefinition(Type implementor, Type serviceType) { return implementor == serviceType || (implementor.IsGenericType && implementor.GetGenericTypeDefinition() == serviceType); diff --git a/src/Autofac/Features/Scanning/OpenGenericScanningRegistrationExtensions.cs b/src/Autofac/Features/Scanning/OpenGenericScanningRegistrationExtensions.cs index 0c9673072..2a7a95213 100644 --- a/src/Autofac/Features/Scanning/OpenGenericScanningRegistrationExtensions.cs +++ b/src/Autofac/Features/Scanning/OpenGenericScanningRegistrationExtensions.cs @@ -86,26 +86,6 @@ public static IRegistrationBuilder assemblies, IComponentRegistryBuilder cr, IRegistrationBuilder rb) - { - rb.ActivatorData.Filters.Add(t => - rb.RegistrationData.Services.OfType().All(swt => - t.IsOpenGenericTypeOf(swt.ServiceType))); - - var types = assemblies.SelectMany(a => a.GetPermittedTypesForAssemblyScanning()) - .Where(t => t.IsGenericTypeDefinition) - .AllowedByActivatorFilters(rb.ActivatorData); - - static IRegistrationBuilder TypeBuilderFactory(Type type) => new RegistrationBuilder( - new TypedService(type), - new ReflectionActivatorData(type), - new DynamicRegistrationStyle()); - - static void RegistrationSourceFactory(IComponentRegistryBuilder registry, IRegistrationBuilder data) => registry.AddRegistrationSource(new OpenGenericRegistrationSource(data.RegistrationData, data.ResolvePipeline, data.ActivatorData)); - - types.RegisterUsingTemplate(cr, rb, TypeBuilderFactory, RegistrationSourceFactory); - } - /// /// Filters the scanned types to include only those assignable to the provided. /// @@ -181,4 +161,24 @@ public static IRegistrationBuilder candidateType.IsOpenGenericTypeOf(openGenericServiceType)) .As(candidateType => (Service)new KeyedService(serviceKeyMapping(candidateType), candidateType)); } + + private static void ScanAssembliesForOpenGenerics(IEnumerable assemblies, IComponentRegistryBuilder cr, IRegistrationBuilder rb) + { + rb.ActivatorData.Filters.Add(t => + rb.RegistrationData.Services.OfType().All(swt => + t.IsOpenGenericTypeOf(swt.ServiceType))); + + var types = assemblies.SelectMany(a => a.GetPermittedTypesForAssemblyScanning()) + .Where(t => t.IsGenericTypeDefinition) + .AllowedByActivatorFilters(rb.ActivatorData); + + static IRegistrationBuilder TypeBuilderFactory(Type type) => new RegistrationBuilder( + new TypedService(type), + new ReflectionActivatorData(type), + new DynamicRegistrationStyle()); + + static void RegistrationSourceFactory(IComponentRegistryBuilder registry, IRegistrationBuilder data) => registry.AddRegistrationSource(new OpenGenericRegistrationSource(data.RegistrationData, data.ResolvePipeline, data.ActivatorData)); + + types.RegisterUsingTemplate(cr, rb, TypeBuilderFactory, RegistrationSourceFactory); + } } diff --git a/src/Autofac/RegistrationExtensions.AssemblyScanning.cs b/src/Autofac/RegistrationExtensions.AssemblyScanning.cs index 9324e6138..892748a71 100644 --- a/src/Autofac/RegistrationExtensions.AssemblyScanning.cs +++ b/src/Autofac/RegistrationExtensions.AssemblyScanning.cs @@ -235,20 +235,6 @@ public static IRegistrationBuilder i != typeof(IDisposable)); - return type.IsInterface ? interfaces.AppendItem(type).ToArray() : interfaces.ToArray(); - } - - private static Type[] GetOpenGenericImplementedInterfaces(this Type @this) - { - return @this.GetInterfaces() - .Where(it => it.IsGenericType) - .Select(it => it.GetGenericTypeDefinition()) - .ToArray(); - } - /// /// Specifies that the components being registered should only be made the default for services /// that have not already been registered. @@ -473,4 +459,18 @@ public static IRegistrationBuilder i != typeof(IDisposable)); + return type.IsInterface ? interfaces.AppendItem(type).ToArray() : interfaces.ToArray(); + } + + private static Type[] GetOpenGenericImplementedInterfaces(this Type @this) + { + return @this.GetInterfaces() + .Where(it => it.IsGenericType) + .Select(it => it.GetGenericTypeDefinition()) + .ToArray(); + } } diff --git a/src/Autofac/Util/Disposable.cs b/src/Autofac/Util/Disposable.cs index 234ed1465..184b35371 100644 --- a/src/Autofac/Util/Disposable.cs +++ b/src/Autofac/Util/Disposable.cs @@ -39,14 +39,6 @@ public void Dispose() GC.SuppressFinalize(this); } - /// - /// Releases unmanaged and - optionally - managed resources. - /// - /// to release both managed and unmanaged resources; to release only unmanaged resources. - protected virtual void Dispose(bool disposing) - { - } - /// [SuppressMessage( "Usage", @@ -68,6 +60,14 @@ public ValueTask DisposeAsync() return default; } + /// + /// Releases unmanaged and - optionally - managed resources. + /// + /// to release both managed and unmanaged resources; to release only unmanaged resources. + protected virtual void Dispose(bool disposing) + { + } + /// /// Releases unmanaged and - optionally - managed resources, asynchronously. /// From 43866ce4b1764965fb1bd782033981badd490ad2 Mon Sep 17 00:00:00 2001 From: Travis Illig Date: Thu, 18 Sep 2025 11:38:17 -0700 Subject: [PATCH 12/15] Enabled no copy/paste docs rule. --- build/Source.ruleset | 2 -- src/Autofac/Builder/IRegistrationBuilder.cs | 10 +++++----- ...uilder{TLimit,TActivatorData,TRegistrationStyle}.cs | 10 +++++----- src/Autofac/Builder/RegistrationOrderExtensions.cs | 2 +- .../OpenGenericScanningRegistrationExtensions.cs | 6 +++--- .../Scanning/ScanningRegistrationExtensions.cs | 6 +++--- 6 files changed, 17 insertions(+), 19 deletions(-) diff --git a/build/Source.ruleset b/build/Source.ruleset index 1975e6ce2..ee2207d60 100644 --- a/build/Source.ruleset +++ b/build/Source.ruleset @@ -28,7 +28,5 @@ - - diff --git a/src/Autofac/Builder/IRegistrationBuilder.cs b/src/Autofac/Builder/IRegistrationBuilder.cs index 0cc0c1ba9..f76e252d0 100644 --- a/src/Autofac/Builder/IRegistrationBuilder.cs +++ b/src/Autofac/Builder/IRegistrationBuilder.cs @@ -156,8 +156,8 @@ IRegistrationBuilder As() /// Configure the services that the component will provide. The generic parameter(s) to As() /// will be exposed as TypedService instances. /// - /// Service type. - /// Service type. + /// First service type. + /// Second service type. /// A registration builder allowing further configuration of the component. IRegistrationBuilder As() where TService1 : notnull @@ -167,9 +167,9 @@ IRegistrationBuilder As - /// Service type. - /// Service type. - /// Service type. + /// First service type. + /// Second service type. + /// Third service type. /// A registration builder allowing further configuration of the component. IRegistrationBuilder As() where TService1 : notnull diff --git a/src/Autofac/Builder/RegistrationBuilder{TLimit,TActivatorData,TRegistrationStyle}.cs b/src/Autofac/Builder/RegistrationBuilder{TLimit,TActivatorData,TRegistrationStyle}.cs index 012010044..6cd15735e 100644 --- a/src/Autofac/Builder/RegistrationBuilder{TLimit,TActivatorData,TRegistrationStyle}.cs +++ b/src/Autofac/Builder/RegistrationBuilder{TLimit,TActivatorData,TRegistrationStyle}.cs @@ -238,8 +238,8 @@ public IRegistrationBuilder As - /// Service type. - /// Service type. + /// First service type. + /// Second service type. /// A registration builder allowing further configuration of the component. public IRegistrationBuilder As() where TService1 : notnull @@ -252,9 +252,9 @@ public IRegistrationBuilder As - /// Service type. - /// Service type. - /// Service type. + /// First service type. + /// Second service type. + /// Third service type. /// A registration builder allowing further configuration of the component. public IRegistrationBuilder As() where TService1 : notnull diff --git a/src/Autofac/Builder/RegistrationOrderExtensions.cs b/src/Autofac/Builder/RegistrationOrderExtensions.cs index f50ff57bf..6d84daed5 100644 --- a/src/Autofac/Builder/RegistrationOrderExtensions.cs +++ b/src/Autofac/Builder/RegistrationOrderExtensions.cs @@ -28,7 +28,7 @@ internal static long GetRegistrationOrder(this IComponentRegistration registrati /// The registration style type. /// The registration builder. /// The source registration to take the order from. - /// The registration builder. + /// The registration builder for continued configuration. internal static IRegistrationBuilder InheritRegistrationOrderFrom( this IRegistrationBuilder registration, IComponentRegistration source) diff --git a/src/Autofac/Features/Scanning/OpenGenericScanningRegistrationExtensions.cs b/src/Autofac/Features/Scanning/OpenGenericScanningRegistrationExtensions.cs index 2a7a95213..e3d9854de 100644 --- a/src/Autofac/Features/Scanning/OpenGenericScanningRegistrationExtensions.cs +++ b/src/Autofac/Features/Scanning/OpenGenericScanningRegistrationExtensions.cs @@ -93,7 +93,7 @@ public static IRegistrationBuilderThe registration style. /// The registration builder. /// The type or interface which all classes must be assignable from. - /// The registration builder. + /// The registration builder for continued configuration. public static IRegistrationBuilder AssignableTo( IRegistrationBuilder registration, @@ -117,7 +117,7 @@ public static IRegistrationBuilderThe registration builder. /// The type or interface which all classes must be assignable from. /// The service key. - /// The registration builder. + /// The registration builder for continued configuration. public static IRegistrationBuilder AssignableTo( IRegistrationBuilder registration, @@ -145,7 +145,7 @@ public static IRegistrationBuilderThe registration builder. /// The type or interface which all classes must be assignable from. /// A function to determine the service key for a given type. - /// The registration builder. + /// The registration builder for continued configuration. public static IRegistrationBuilder AssignableTo( IRegistrationBuilder registration, diff --git a/src/Autofac/Features/Scanning/ScanningRegistrationExtensions.cs b/src/Autofac/Features/Scanning/ScanningRegistrationExtensions.cs index 78ab4e013..23bd5c56b 100644 --- a/src/Autofac/Features/Scanning/ScanningRegistrationExtensions.cs +++ b/src/Autofac/Features/Scanning/ScanningRegistrationExtensions.cs @@ -80,7 +80,7 @@ public static IRegistrationBuilderThe registration style. /// The registration builder. /// The open generic to register closed types of. - /// The registration builder. + /// The registration builder for continued configuration. public static IRegistrationBuilder AsClosedTypesOf( IRegistrationBuilder registration, @@ -107,7 +107,7 @@ public static IRegistrationBuilderThe registration builder. /// The open generic to register closed types of. /// The service key. - /// The registration builder. + /// The registration builder for continued configuration. public static IRegistrationBuilder AsClosedTypesOf( IRegistrationBuilder registration, @@ -137,7 +137,7 @@ public static IRegistrationBuilderThe registration builder. /// The open generic to register closed types of. /// A function to determine the service key for a given type. - /// The registration builder. + /// The registration builder for continued configuration. public static IRegistrationBuilder AsClosedTypesOf( IRegistrationBuilder registration, From e49500cfb636b96281c602bfe84181ad8d842644 Mon Sep 17 00:00:00 2001 From: Travis Illig Date: Thu, 18 Sep 2025 11:41:46 -0700 Subject: [PATCH 13/15] Enabled rules to catch complex code. --- build/Source.ruleset | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/build/Source.ruleset b/build/Source.ruleset index ee2207d60..f337c977a 100644 --- a/build/Source.ruleset +++ b/build/Source.ruleset @@ -4,6 +4,14 @@ + + + + + + + + From 05384fa4a020240fe943bf11448bb6e04cf1a44a Mon Sep 17 00:00:00 2001 From: Travis Illig Date: Thu, 18 Sep 2025 11:52:16 -0700 Subject: [PATCH 14/15] Enabled rules for catching code issues in tests. --- build/Test.ruleset | 34 +++++++++---------- .../Features/PropertyInjectionTests.cs | 4 +-- .../AutofacCompile.cs | 4 +-- ...eightAdapterRegistrationExtensionsTests.cs | 2 +- 4 files changed, 21 insertions(+), 23 deletions(-) diff --git a/build/Test.ruleset b/build/Test.ruleset index e119e9e23..7549ea059 100644 --- a/build/Test.ruleset +++ b/build/Test.ruleset @@ -2,6 +2,8 @@ + + @@ -10,6 +12,12 @@ + + + + + + @@ -44,28 +52,22 @@ - - - + - + - - - + - - - - - - - + + + + + @@ -74,10 +76,6 @@ - - - - diff --git a/test/Autofac.Specification.Test/Features/PropertyInjectionTests.cs b/test/Autofac.Specification.Test/Features/PropertyInjectionTests.cs index b95b74bc8..f8e544294 100644 --- a/test/Autofac.Specification.Test/Features/PropertyInjectionTests.cs +++ b/test/Autofac.Specification.Test/Features/PropertyInjectionTests.cs @@ -433,8 +433,8 @@ public void WithPropertyTypedAllowsNullValue() private class ConstructorParamNotAttachedToProperty { - [SuppressMessage("SA1401", "SA1401")] - public string _id = null; + [SuppressMessage("SA1401", "SA1401", Justification = "Field access used in test.")] + public string _id; public ConstructorParamNotAttachedToProperty(string id) { diff --git a/test/Autofac.Test.Compilation/AutofacCompile.cs b/test/Autofac.Test.Compilation/AutofacCompile.cs index cb3b0ca53..9e242669b 100644 --- a/test/Autofac.Test.Compilation/AutofacCompile.cs +++ b/test/Autofac.Test.Compilation/AutofacCompile.cs @@ -16,8 +16,6 @@ namespace Autofac.Test.Compilation; /// public class AutofacCompile { - private string? _body; - private readonly List _references = new() { // Bring in the appropriate SDK package @@ -28,6 +26,8 @@ public class AutofacCompile MetadataReference.CreateFromFile(typeof(AutofacCompile).Assembly.Location), }; + private string? _body; + public AutofacCompile Body(string body) { _body = body; diff --git a/test/Autofac.Test/Features/LightweightAdapters/LightweightAdapterRegistrationExtensionsTests.cs b/test/Autofac.Test/Features/LightweightAdapters/LightweightAdapterRegistrationExtensionsTests.cs index 3e2049a1d..252a6724e 100644 --- a/test/Autofac.Test/Features/LightweightAdapters/LightweightAdapterRegistrationExtensionsTests.cs +++ b/test/Autofac.Test/Features/LightweightAdapters/LightweightAdapterRegistrationExtensionsTests.cs @@ -66,9 +66,9 @@ public void EachInstanceOfTheTargetTypeIsAdapted() [SuppressMessage("CA1034", "CA1034", Justification = "Type is used as a test scenario/context holder.")] public class OnTopOfAnotherAdapter { - private readonly Command _from = new(); private const string NameKey = "Name"; private const string Name = "N"; + private readonly Command _from = new(); private readonly ToolbarButton _to; public OnTopOfAnotherAdapter() From 10ceccaa4157b8daf16a67ae27a52fec15e1d6c9 Mon Sep 17 00:00:00 2001 From: Travis Illig Date: Thu, 18 Sep 2025 11:53:58 -0700 Subject: [PATCH 15/15] Avoid excessive class coupling in tests. --- build/Test.ruleset | 2 ++ 1 file changed, 2 insertions(+) diff --git a/build/Test.ruleset b/build/Test.ruleset index 7549ea059..458fa070a 100644 --- a/build/Test.ruleset +++ b/build/Test.ruleset @@ -18,6 +18,8 @@ + +