Skip to content

Commit a518a48

Browse files
authored
Merge pull request #1397 from SergeiPavlov/struct_ResolveRequest
Optimization: convert `ResolveRequest` into readonly struct
2 parents e61a651 + 095a0c3 commit a518a48

18 files changed

+58
-45
lines changed

src/Autofac/Core/Container.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,7 @@ public event EventHandler<ResolveOperationBeginningEventArgs> ResolveOperationBe
140140
public IComponentRegistry ComponentRegistry { get; }
141141

142142
/// <inheritdoc />
143-
public object ResolveComponent(ResolveRequest request)
143+
public object ResolveComponent(in ResolveRequest request)
144144
{
145145
return _rootLifetimeScope.ResolveComponent(request);
146146
}

src/Autofac/Core/ImplicitRegistrationSource.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ public IEnumerable<IComponentRegistration> RegistrationsFor(Service service, Fun
8686
/// <param name="ctx">A component context to resolve services.</param>
8787
/// <param name="request">A resolve request.</param>
8888
/// <returns>An implicit type instance.</returns>
89-
protected abstract object ResolveInstance<T>(IComponentContext ctx, ResolveRequest request)
89+
protected abstract object ResolveInstance<T>(IComponentContext ctx, in ResolveRequest request)
9090
where T : notnull;
9191

9292
/// <summary>

src/Autofac/Core/Lifetime/LifetimeScope.cs

+1-6
Original file line numberDiff line numberDiff line change
@@ -323,13 +323,8 @@ private ComponentRegistryBuilder CreateScopeRestrictedRegistry(object tag, Actio
323323
}
324324

325325
/// <inheritdoc />
326-
public object ResolveComponent(ResolveRequest request)
326+
public object ResolveComponent(in ResolveRequest request)
327327
{
328-
if (request == null)
329-
{
330-
throw new ArgumentNullException(nameof(request));
331-
}
332-
333328
CheckNotDisposed();
334329

335330
var operation = new ResolveOperation(this, DiagnosticSource);

src/Autofac/Core/Resolving/IResolveOperation.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -59,5 +59,5 @@ public interface IResolveOperation
5959
/// <param name="currentOperationScope">The scope in the hierarchy in which the operation will begin.</param>
6060
/// <param name="request">The resolve request.</param>
6161
/// <returns>The component instance.</returns>
62-
object GetOrCreateInstance(ISharingLifetimeScope currentOperationScope, ResolveRequest request);
62+
object GetOrCreateInstance(ISharingLifetimeScope currentOperationScope, in ResolveRequest request);
6363
}

src/Autofac/Core/Resolving/Pipeline/DefaultResolveRequestContext.cs

+3-3
Original file line numberDiff line numberDiff line change
@@ -25,14 +25,14 @@ internal sealed class DefaultResolveRequestContext : ResolveRequestContext
2525
/// </param>
2626
internal DefaultResolveRequestContext(
2727
IResolveOperation owningOperation,
28-
ResolveRequest request,
28+
in ResolveRequest request,
2929
ISharingLifetimeScope scope,
3030
DiagnosticListener diagnosticSource)
3131
{
3232
Operation = owningOperation;
3333
ActivationScope = scope;
3434
Parameters = request.Parameters;
35-
_resolveRequest = request ?? throw new ArgumentNullException(nameof(request));
35+
_resolveRequest = request;
3636
PhaseReached = PipelinePhase.ResolveRequestStart;
3737
DiagnosticSource = diagnosticSource;
3838
}
@@ -90,7 +90,7 @@ public override void ChangeParameters(IEnumerable<Parameter> newParameters) =>
9090
Parameters = newParameters ?? throw new ArgumentNullException(nameof(newParameters));
9191

9292
/// <inheritdoc />
93-
public override object ResolveComponent(ResolveRequest request) =>
93+
public override object ResolveComponent(in ResolveRequest request) =>
9494
Operation.GetOrCreateInstance(ActivationScope, request);
9595

9696
/// <summary>

src/Autofac/Core/Resolving/Pipeline/ResolveRequestContext.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -95,5 +95,5 @@ public abstract class ResolveRequestContext : IComponentContext
9595
public abstract IComponentRegistry ComponentRegistry { get; }
9696

9797
/// <inheritdoc/>
98-
public abstract object ResolveComponent(ResolveRequest request);
98+
public abstract object ResolveComponent(in ResolveRequest request);
9999
}

src/Autofac/Core/Resolving/ResolveOperation.cs

+4-9
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ public ResolveOperation(
4242
/// Execute the complete resolve operation.
4343
/// </summary>
4444
/// <param name="request">The resolution context.</param>
45-
public object Execute(ResolveRequest request)
45+
public object Execute(in ResolveRequest request)
4646
{
4747
return ExecuteOperation(request);
4848
}
@@ -93,13 +93,8 @@ public object Execute(ResolveRequest request)
9393
public SegmentedStack<ResolveRequestContext> RequestStack { get; } = new SegmentedStack<ResolveRequestContext>();
9494

9595
/// <inheritdoc />
96-
public object GetOrCreateInstance(ISharingLifetimeScope currentOperationScope, ResolveRequest request)
96+
public object GetOrCreateInstance(ISharingLifetimeScope currentOperationScope, in ResolveRequest request)
9797
{
98-
if (request is null)
99-
{
100-
throw new ArgumentNullException(nameof(request));
101-
}
102-
10398
if (_ended)
10499
{
105100
throw new ObjectDisposedException(ResolveOperationResources.TemporaryContextDisposed, innerException: null);
@@ -170,7 +165,7 @@ public object GetOrCreateInstance(ISharingLifetimeScope currentOperationScope, R
170165
/// </summary>
171166
/// <param name="request">The resolve request.</param>
172167
/// <returns>The resolved instance.</returns>
173-
private object ExecuteOperation(ResolveRequest request)
168+
private object ExecuteOperation(in ResolveRequest request)
174169
{
175170
object result;
176171

@@ -233,7 +228,7 @@ private object ExecuteOperation(ResolveRequest request)
233228
/// to enable it to be optionally surrounded with diagnostics.
234229
/// </summary>
235230
[MethodImpl(MethodImplOptions.AggressiveInlining)]
236-
private void InvokePipeline(ResolveRequest request, DefaultResolveRequestContext requestContext)
231+
private void InvokePipeline(in ResolveRequest request, DefaultResolveRequestContext requestContext)
237232
{
238233
request.ResolvePipeline.Invoke(requestContext);
239234
if (requestContext.Instance == null)

src/Autofac/Diagnostics/DiagnosticSourceExtensions.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ public static void MiddlewareSuccess(this DiagnosticListener diagnosticSource, R
6060
/// <param name="diagnosticSource">The diagnostic source to which events will be written.</param>
6161
/// <param name="operation">The pipeline resolve operation that is about to run.</param>
6262
/// <param name="initiatingRequest">The request that is responsible for starting this operation.</param>
63-
public static void OperationStart(this DiagnosticListener diagnosticSource, IResolveOperation operation, ResolveRequest initiatingRequest)
63+
public static void OperationStart(this DiagnosticListener diagnosticSource, IResolveOperation operation, in ResolveRequest initiatingRequest)
6464
{
6565
if (diagnosticSource.IsEnabled(DiagnosticEventKeys.OperationStart))
6666
{

src/Autofac/Diagnostics/OperationStartDiagnosticData.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ public class OperationStartDiagnosticData
1515
/// </summary>
1616
/// <param name="operation">The pipeline resolve operation that is about to run.</param>
1717
/// <param name="initiatingRequest">The request that is responsible for starting this operation.</param>
18-
public OperationStartDiagnosticData(IResolveOperation operation, ResolveRequest initiatingRequest)
18+
public OperationStartDiagnosticData(IResolveOperation operation, in ResolveRequest initiatingRequest)
1919
{
2020
Operation = operation;
2121
InitiatingRequest = initiatingRequest;

src/Autofac/Features/Decorators/DecoratorContext.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -78,5 +78,5 @@ internal DecoratorContext UpdateContext(object decoratorInstance)
7878
}
7979

8080
/// <inheritdoc />
81-
public object ResolveComponent(ResolveRequest request) => _componentContext.ResolveComponent(request);
81+
public object ResolveComponent(in ResolveRequest request) => _componentContext.ResolveComponent(request);
8282
}

src/Autofac/Features/LazyDependencies/LazyRegistrationSource.cs

+3-2
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,10 @@ public LazyRegistrationSource()
2525
public override string Description => LazyRegistrationSourceResources.LazyRegistrationSourceDescription;
2626

2727
/// <inheritdoc/>
28-
protected override object ResolveInstance<T>(IComponentContext context, ResolveRequest request)
28+
protected override object ResolveInstance<T>(IComponentContext context, in ResolveRequest request)
2929
{
3030
var capturedContext = context.Resolve<IComponentContext>();
31-
return new Lazy<T>(() => (T)capturedContext.ResolveComponent(request));
31+
ResolveRequest requestCopy = request;
32+
return new Lazy<T>(() => (T)capturedContext.ResolveComponent(requestCopy));
3233
}
3334
}

src/Autofac/Features/Metadata/MetaRegistrationSource.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,6 @@ public MetaRegistrationSource()
2424
public override string Description => MetaRegistrationSourceResources.MetaRegistrationSourceDescription;
2525

2626
/// <inheritdoc/>
27-
protected override object ResolveInstance<T>(IComponentContext ctx, ResolveRequest request)
27+
protected override object ResolveInstance<T>(IComponentContext ctx, in ResolveRequest request)
2828
=> new Meta<T>((T)ctx.ResolveComponent(request), request.Registration.Target.Metadata);
2929
}

src/Autofac/Features/OwnedInstances/OwnedInstanceRegistrationSource.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ public OwnedInstanceRegistrationSource()
2121
}
2222

2323
/// <inheritdoc/>
24-
protected override object ResolveInstance<T>(IComponentContext ctx, ResolveRequest request)
24+
protected override object ResolveInstance<T>(IComponentContext ctx, in ResolveRequest request)
2525
{
2626
var lifetime = ctx.Resolve<ILifetimeScope>().BeginLifetimeScope(request.Service);
2727
try

src/Autofac/IComponentContext.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -27,5 +27,5 @@ public interface IComponentContext
2727
/// </returns>
2828
/// <exception cref="ComponentNotRegisteredException"/>
2929
/// <exception cref="DependencyResolutionException"/>
30-
object ResolveComponent(ResolveRequest request);
30+
object ResolveComponent(in ResolveRequest request);
3131
}

src/Autofac/ResolveRequest.cs

+31-2
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,15 @@ namespace Autofac;
99
/// <summary>
1010
/// The details of an individual request to resolve a service.
1111
/// </summary>
12-
public class ResolveRequest
12+
public readonly struct ResolveRequest : IEquatable<ResolveRequest>
1313
{
1414
/// <summary>
1515
/// Shared constant value defining an empty set of parameters.
1616
/// </summary>
1717
internal static readonly IEnumerable<Parameter> NoParameters = Enumerable.Empty<Parameter>();
1818

1919
/// <summary>
20-
/// Initializes a new instance of the <see cref="ResolveRequest"/> class.
20+
/// Initializes a new instance of the <see cref="ResolveRequest"/> struct.
2121
/// </summary>
2222
/// <param name="service">The service being resolved.</param>
2323
/// <param name="serviceRegistration">The component registration for the service.</param>
@@ -56,4 +56,33 @@ public ResolveRequest(Service service, ServiceRegistration serviceRegistration,
5656
/// Gets the component registration for the decorator target if configured.
5757
/// </summary>
5858
public IComponentRegistration? DecoratorTarget { get; }
59+
60+
/// <inheritdoc/>
61+
public override bool Equals(object? obj) =>
62+
obj is ResolveRequest other && Equals(other);
63+
64+
/// <inheritdoc/>
65+
public bool Equals(ResolveRequest other) =>
66+
Service == other.Service && Registration == other.Registration && ResolvePipeline == other.ResolvePipeline && Parameters == other.Parameters && DecoratorTarget == other.DecoratorTarget;
67+
68+
/// <summary>
69+
/// Implements the operator ==.
70+
/// </summary>
71+
/// <param name="left">The left operand.</param>
72+
/// <param name="right">The right operand.</param>
73+
/// <returns>The result of the operator.</returns>
74+
public static bool operator ==(ResolveRequest left, ResolveRequest right) => Equals(left, right);
75+
76+
/// <summary>
77+
/// Implements the operator !=.
78+
/// </summary>
79+
/// <param name="left">The left operand.</param>
80+
/// <param name="right">The right operand.</param>
81+
/// <returns>The result of the operator.</returns>
82+
public static bool operator !=(ResolveRequest left, ResolveRequest right) =>
83+
!(left == right);
84+
85+
/// <inheritdoc/>
86+
public override int GetHashCode() =>
87+
Service.GetHashCode() ^ Registration.GetHashCode() ^ ResolvePipeline.GetHashCode() ^ Parameters.GetHashCode() ^ (DecoratorTarget?.GetHashCode() ?? 0);
5988
}

test/Autofac.Test/Core/ImplicitRegistrationSourceTests.cs

+2-2
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ public AnyTypeImplicitRegistrationSource(Type type)
109109
{
110110
}
111111

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

115115
private class Mapped<T>
@@ -129,7 +129,7 @@ public MappedImplicitRegistrationSource()
129129
{
130130
}
131131

132-
protected override object ResolveInstance<T>(IComponentContext ctx, ResolveRequest request)
132+
protected override object ResolveInstance<T>(IComponentContext ctx, in ResolveRequest request)
133133
{
134134
return new Mapped<T>((T)ctx.ResolveComponent(request));
135135
}

test/Autofac.Test/Core/Pipeline/PipelineBuilderTests.cs

+2-2
Original file line numberDiff line numberDiff line change
@@ -483,7 +483,7 @@ public override event EventHandler<ResolveRequestCompletingEventArgs> RequestCom
483483

484484
public override IComponentRegistry ComponentRegistry => ActivationScope.ComponentRegistry;
485485

486-
public override object ResolveComponent(ResolveRequest request) => throw new NotImplementedException();
486+
public override object ResolveComponent(in ResolveRequest request) => throw new NotImplementedException();
487487
}
488488

489489
private class LifetimeScopeStub : ISharingLifetimeScope
@@ -566,7 +566,7 @@ public ValueTask DisposeAsync()
566566
throw new NotImplementedException();
567567
}
568568

569-
public object ResolveComponent(ResolveRequest request)
569+
public object ResolveComponent(in ResolveRequest request)
570570
{
571571
throw new NotImplementedException();
572572
}

test/Autofac.Test/Core/Resolving/ResolveOperationTests.cs

+2-9
Original file line numberDiff line numberDiff line change
@@ -33,15 +33,6 @@ public void EmptyInProgressRequestWhenInitializing()
3333
Assert.Empty(inProgressStack);
3434
}
3535

36-
[Fact]
37-
public void GetOrCreateInstanceThrowsArgumentNullExceptionWhenResolveRequestIsNull()
38-
{
39-
var lifetimeScope = Substitute.For<ISharingLifetimeScope>();
40-
var resolveOperation = new ResolveOperation(lifetimeScope, new DiagnosticListener("SomeName"));
41-
42-
Assert.Throws<ArgumentNullException>(() => resolveOperation.GetOrCreateInstance(lifetimeScope, null!));
43-
}
44-
4536
[Fact]
4637
public void AfterTheOperationIsFinished_ReusingTheTemporaryContextThrows()
4738
{
@@ -77,12 +68,14 @@ public void OperationRaisesSuccessTraceEvents()
7768
var raisedEvents = new List<string>();
7869

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

8173
mockTracer.OperationStarting += (op, req) =>
8274
{
8375
raisedEvents.Add("op-start");
8476
Assert.Equal(resolveOp, op);
8577
Assert.Equal(request, req);
78+
Assert.True(req != request2);
8679
};
8780

8881
mockTracer.RequestStarting += (op, context) =>

0 commit comments

Comments
 (0)