Skip to content

Commit

Permalink
Merge pull request #1397 from SergeiPavlov/struct_ResolveRequest
Browse files Browse the repository at this point in the history
Optimization: convert `ResolveRequest` into readonly struct
  • Loading branch information
tillig committed Nov 15, 2023
2 parents e61a651 + 095a0c3 commit a518a48
Show file tree
Hide file tree
Showing 18 changed files with 58 additions and 45 deletions.
2 changes: 1 addition & 1 deletion src/Autofac/Core/Container.cs
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ public ILifetimeScope BeginLoadContextLifetimeScope(object tag, AssemblyLoadCont
public IComponentRegistry ComponentRegistry { get; }

/// <inheritdoc />
public object ResolveComponent(ResolveRequest request)
public object ResolveComponent(in ResolveRequest request)
{
return _rootLifetimeScope.ResolveComponent(request);
}
Expand Down
2 changes: 1 addition & 1 deletion src/Autofac/Core/ImplicitRegistrationSource.cs
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ public IEnumerable<IComponentRegistration> RegistrationsFor(Service service, Fun
/// <param name="ctx">A component context to resolve services.</param>
/// <param name="request">A resolve request.</param>
/// <returns>An implicit type instance.</returns>
protected abstract object ResolveInstance<T>(IComponentContext ctx, ResolveRequest request)
protected abstract object ResolveInstance<T>(IComponentContext ctx, in ResolveRequest request)
where T : notnull;

/// <summary>
Expand Down
7 changes: 1 addition & 6 deletions src/Autofac/Core/Lifetime/LifetimeScope.cs
Original file line number Diff line number Diff line change
Expand Up @@ -323,13 +323,8 @@ private ComponentRegistryBuilder CreateScopeRestrictedRegistry(object tag, Actio
}

/// <inheritdoc />
public object ResolveComponent(ResolveRequest request)
public object ResolveComponent(in ResolveRequest request)
{
if (request == null)
{
throw new ArgumentNullException(nameof(request));
}

CheckNotDisposed();

var operation = new ResolveOperation(this, DiagnosticSource);
Expand Down
2 changes: 1 addition & 1 deletion src/Autofac/Core/Resolving/IResolveOperation.cs
Original file line number Diff line number Diff line change
Expand Up @@ -59,5 +59,5 @@ public interface IResolveOperation
/// <param name="currentOperationScope">The scope in the hierarchy in which the operation will begin.</param>
/// <param name="request">The resolve request.</param>
/// <returns>The component instance.</returns>
object GetOrCreateInstance(ISharingLifetimeScope currentOperationScope, ResolveRequest request);
object GetOrCreateInstance(ISharingLifetimeScope currentOperationScope, in ResolveRequest request);
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,14 +25,14 @@ internal sealed class DefaultResolveRequestContext : ResolveRequestContext
/// </param>
internal DefaultResolveRequestContext(
IResolveOperation owningOperation,
ResolveRequest request,
in ResolveRequest request,
ISharingLifetimeScope scope,
DiagnosticListener diagnosticSource)
{
Operation = owningOperation;
ActivationScope = scope;
Parameters = request.Parameters;
_resolveRequest = request ?? throw new ArgumentNullException(nameof(request));
_resolveRequest = request;
PhaseReached = PipelinePhase.ResolveRequestStart;
DiagnosticSource = diagnosticSource;
}
Expand Down Expand Up @@ -90,7 +90,7 @@ internal sealed class DefaultResolveRequestContext : ResolveRequestContext
Parameters = newParameters ?? throw new ArgumentNullException(nameof(newParameters));

/// <inheritdoc />
public override object ResolveComponent(ResolveRequest request) =>
public override object ResolveComponent(in ResolveRequest request) =>
Operation.GetOrCreateInstance(ActivationScope, request);

/// <summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -95,5 +95,5 @@ public abstract class ResolveRequestContext : IComponentContext
public abstract IComponentRegistry ComponentRegistry { get; }

/// <inheritdoc/>
public abstract object ResolveComponent(ResolveRequest request);
public abstract object ResolveComponent(in ResolveRequest request);
}
13 changes: 4 additions & 9 deletions src/Autofac/Core/Resolving/ResolveOperation.cs
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ internal sealed class ResolveOperation : IDependencyTrackingResolveOperation
/// Execute the complete resolve operation.
/// </summary>
/// <param name="request">The resolution context.</param>
public object Execute(ResolveRequest request)
public object Execute(in ResolveRequest request)
{
return ExecuteOperation(request);
}
Expand Down Expand Up @@ -93,13 +93,8 @@ public object Execute(ResolveRequest request)
public SegmentedStack<ResolveRequestContext> RequestStack { get; } = new SegmentedStack<ResolveRequestContext>();

/// <inheritdoc />
public object GetOrCreateInstance(ISharingLifetimeScope currentOperationScope, ResolveRequest request)
public object GetOrCreateInstance(ISharingLifetimeScope currentOperationScope, in ResolveRequest request)
{
if (request is null)
{
throw new ArgumentNullException(nameof(request));
}

if (_ended)
{
throw new ObjectDisposedException(ResolveOperationResources.TemporaryContextDisposed, innerException: null);
Expand Down Expand Up @@ -170,7 +165,7 @@ public object GetOrCreateInstance(ISharingLifetimeScope currentOperationScope, R
/// </summary>
/// <param name="request">The resolve request.</param>
/// <returns>The resolved instance.</returns>
private object ExecuteOperation(ResolveRequest request)
private object ExecuteOperation(in ResolveRequest request)
{
object result;

Expand Down Expand Up @@ -233,7 +228,7 @@ private object ExecuteOperation(ResolveRequest request)
/// to enable it to be optionally surrounded with diagnostics.
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void InvokePipeline(ResolveRequest request, DefaultResolveRequestContext requestContext)
private void InvokePipeline(in ResolveRequest request, DefaultResolveRequestContext requestContext)
{
request.ResolvePipeline.Invoke(requestContext);
if (requestContext.Instance == null)
Expand Down
2 changes: 1 addition & 1 deletion src/Autofac/Diagnostics/DiagnosticSourceExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ public static void MiddlewareSuccess(this DiagnosticListener diagnosticSource, R
/// <param name="diagnosticSource">The diagnostic source to which events will be written.</param>
/// <param name="operation">The pipeline resolve operation that is about to run.</param>
/// <param name="initiatingRequest">The request that is responsible for starting this operation.</param>
public static void OperationStart(this DiagnosticListener diagnosticSource, IResolveOperation operation, ResolveRequest initiatingRequest)
public static void OperationStart(this DiagnosticListener diagnosticSource, IResolveOperation operation, in ResolveRequest initiatingRequest)
{
if (diagnosticSource.IsEnabled(DiagnosticEventKeys.OperationStart))
{
Expand Down
2 changes: 1 addition & 1 deletion src/Autofac/Diagnostics/OperationStartDiagnosticData.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ public class OperationStartDiagnosticData
/// </summary>
/// <param name="operation">The pipeline resolve operation that is about to run.</param>
/// <param name="initiatingRequest">The request that is responsible for starting this operation.</param>
public OperationStartDiagnosticData(IResolveOperation operation, ResolveRequest initiatingRequest)
public OperationStartDiagnosticData(IResolveOperation operation, in ResolveRequest initiatingRequest)
{
Operation = operation;
InitiatingRequest = initiatingRequest;
Expand Down
2 changes: 1 addition & 1 deletion src/Autofac/Features/Decorators/DecoratorContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -78,5 +78,5 @@ internal DecoratorContext UpdateContext(object decoratorInstance)
}

/// <inheritdoc />
public object ResolveComponent(ResolveRequest request) => _componentContext.ResolveComponent(request);
public object ResolveComponent(in ResolveRequest request) => _componentContext.ResolveComponent(request);
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,10 @@ public LazyRegistrationSource()
public override string Description => LazyRegistrationSourceResources.LazyRegistrationSourceDescription;

/// <inheritdoc/>
protected override object ResolveInstance<T>(IComponentContext context, ResolveRequest request)
protected override object ResolveInstance<T>(IComponentContext context, in ResolveRequest request)
{
var capturedContext = context.Resolve<IComponentContext>();
return new Lazy<T>(() => (T)capturedContext.ResolveComponent(request));
ResolveRequest requestCopy = request;
return new Lazy<T>(() => (T)capturedContext.ResolveComponent(requestCopy));
}
}
2 changes: 1 addition & 1 deletion src/Autofac/Features/Metadata/MetaRegistrationSource.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,6 @@ public MetaRegistrationSource()
public override string Description => MetaRegistrationSourceResources.MetaRegistrationSourceDescription;

/// <inheritdoc/>
protected override object ResolveInstance<T>(IComponentContext ctx, ResolveRequest request)
protected override object ResolveInstance<T>(IComponentContext ctx, in ResolveRequest request)
=> new Meta<T>((T)ctx.ResolveComponent(request), request.Registration.Target.Metadata);
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ public OwnedInstanceRegistrationSource()
}

/// <inheritdoc/>
protected override object ResolveInstance<T>(IComponentContext ctx, ResolveRequest request)
protected override object ResolveInstance<T>(IComponentContext ctx, in ResolveRequest request)
{
var lifetime = ctx.Resolve<ILifetimeScope>().BeginLifetimeScope(request.Service);
try
Expand Down
2 changes: 1 addition & 1 deletion src/Autofac/IComponentContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,5 +27,5 @@ public interface IComponentContext
/// </returns>
/// <exception cref="ComponentNotRegisteredException"/>
/// <exception cref="DependencyResolutionException"/>
object ResolveComponent(ResolveRequest request);
object ResolveComponent(in ResolveRequest request);
}
33 changes: 31 additions & 2 deletions src/Autofac/ResolveRequest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,15 @@ namespace Autofac;
/// <summary>
/// The details of an individual request to resolve a service.
/// </summary>
public class ResolveRequest
public readonly struct ResolveRequest : IEquatable<ResolveRequest>
{
/// <summary>
/// Shared constant value defining an empty set of parameters.
/// </summary>
internal static readonly IEnumerable<Parameter> NoParameters = Enumerable.Empty<Parameter>();

/// <summary>
/// Initializes a new instance of the <see cref="ResolveRequest"/> class.
/// Initializes a new instance of the <see cref="ResolveRequest"/> struct.
/// </summary>
/// <param name="service">The service being resolved.</param>
/// <param name="serviceRegistration">The component registration for the service.</param>
Expand Down Expand Up @@ -56,4 +56,33 @@ public ResolveRequest(Service service, ServiceRegistration serviceRegistration,
/// Gets the component registration for the decorator target if configured.
/// </summary>
public IComponentRegistration? DecoratorTarget { get; }

/// <inheritdoc/>
public override bool Equals(object? obj) =>
obj is ResolveRequest other && Equals(other);

/// <inheritdoc/>
public bool Equals(ResolveRequest other) =>
Service == other.Service && Registration == other.Registration && ResolvePipeline == other.ResolvePipeline && Parameters == other.Parameters && DecoratorTarget == other.DecoratorTarget;

/// <summary>
/// Implements the operator ==.
/// </summary>
/// <param name="left">The left operand.</param>
/// <param name="right">The right operand.</param>
/// <returns>The result of the operator.</returns>
public static bool operator ==(ResolveRequest left, ResolveRequest right) => Equals(left, right);

/// <summary>
/// Implements the operator !=.
/// </summary>
/// <param name="left">The left operand.</param>
/// <param name="right">The right operand.</param>
/// <returns>The result of the operator.</returns>
public static bool operator !=(ResolveRequest left, ResolveRequest right) =>
!(left == right);

/// <inheritdoc/>
public override int GetHashCode() =>
Service.GetHashCode() ^ Registration.GetHashCode() ^ ResolvePipeline.GetHashCode() ^ Parameters.GetHashCode() ^ (DecoratorTarget?.GetHashCode() ?? 0);
}
4 changes: 2 additions & 2 deletions test/Autofac.Test/Core/ImplicitRegistrationSourceTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ public AnyTypeImplicitRegistrationSource(Type type)
{
}

protected override object ResolveInstance<T>(IComponentContext ctx, ResolveRequest request) => throw new NotImplementedException();
protected override object ResolveInstance<T>(IComponentContext ctx, in ResolveRequest request) => throw new NotImplementedException();
}

private class Mapped<T>
Expand All @@ -129,7 +129,7 @@ public MappedImplicitRegistrationSource()
{
}

protected override object ResolveInstance<T>(IComponentContext ctx, ResolveRequest request)
protected override object ResolveInstance<T>(IComponentContext ctx, in ResolveRequest request)
{
return new Mapped<T>((T)ctx.ResolveComponent(request));
}
Expand Down
4 changes: 2 additions & 2 deletions test/Autofac.Test/Core/Pipeline/PipelineBuilderTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -483,7 +483,7 @@ protected set

public override IComponentRegistry ComponentRegistry => ActivationScope.ComponentRegistry;

public override object ResolveComponent(ResolveRequest request) => throw new NotImplementedException();
public override object ResolveComponent(in ResolveRequest request) => throw new NotImplementedException();
}

private class LifetimeScopeStub : ISharingLifetimeScope
Expand Down Expand Up @@ -566,7 +566,7 @@ public ValueTask DisposeAsync()
throw new NotImplementedException();
}

public object ResolveComponent(ResolveRequest request)
public object ResolveComponent(in ResolveRequest request)
{
throw new NotImplementedException();
}
Expand Down
11 changes: 2 additions & 9 deletions test/Autofac.Test/Core/Resolving/ResolveOperationTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,15 +33,6 @@ public void EmptyInProgressRequestWhenInitializing()
Assert.Empty(inProgressStack);
}

[Fact]
public void GetOrCreateInstanceThrowsArgumentNullExceptionWhenResolveRequestIsNull()
{
var lifetimeScope = Substitute.For<ISharingLifetimeScope>();
var resolveOperation = new ResolveOperation(lifetimeScope, new DiagnosticListener("SomeName"));

Assert.Throws<ArgumentNullException>(() => resolveOperation.GetOrCreateInstance(lifetimeScope, null!));
}

[Fact]
public void AfterTheOperationIsFinished_ReusingTheTemporaryContextThrows()
{
Expand Down Expand Up @@ -77,12 +68,14 @@ public void OperationRaisesSuccessTraceEvents()
var raisedEvents = new List<string>();

var request = new ResolveRequest(new TypedService(typeof(string)), scope.ResolvableImplementationFor<string>(), Enumerable.Empty<Parameter>());
var request2 = new ResolveRequest(new TypedService(typeof(int)), scope.ResolvableImplementationFor<string>(), Enumerable.Empty<Parameter>());

mockTracer.OperationStarting += (op, req) =>
{
raisedEvents.Add("op-start");
Assert.Equal(resolveOp, op);
Assert.Equal(request, req);
Assert.True(req != request2);
};

mockTracer.RequestStarting += (op, context) =>
Expand Down

0 comments on commit a518a48

Please sign in to comment.