Skip to content

Commit e511c06

Browse files
committed
Refactor to use a parameter type instead of wrapper collection.
1 parent 03da42d commit e511c06

6 files changed

Lines changed: 86 additions & 100 deletions

File tree

src/Autofac/Core/IKeyedServiceKeyAccessor.cs

Lines changed: 0 additions & 17 deletions
This file was deleted.
Lines changed: 16 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,12 @@
11
// Copyright (c) Autofac Project. All rights reserved.
22
// Licensed under the MIT License. See LICENSE in the project root for license information.
33

4-
using System.Collections;
5-
using System.Reflection;
6-
74
namespace Autofac.Core;
85

96
/// <summary>
107
/// Helper methods for ensuring keyed resolve requests carry the requested key as a parameter.
118
/// </summary>
12-
internal static partial class KeyedServiceParameterInjector
9+
internal static class KeyedServiceParameterInjector
1310
{
1411
/// <summary>
1512
/// Ensures keyed service requests carry their associated key with the parameter sequence.
@@ -29,7 +26,7 @@ public static IEnumerable<Parameter> AddKeyedServiceParameter(Service service, I
2926
return parameters ?? throw new ArgumentNullException(nameof(parameters));
3027
}
3128

32-
return EnsureKeyedServiceParameter(keyedService.ServiceKey, parameters);
29+
return AddKeyedServiceParameter(keyedService.ServiceKey, parameters);
3330
}
3431

3532
/// <summary>
@@ -38,7 +35,7 @@ public static IEnumerable<Parameter> AddKeyedServiceParameter(Service service, I
3835
/// <param name="serviceKey">The keyed service key.</param>
3936
/// <param name="parameters">The parameters supplied by the caller.</param>
4037
/// <returns>An enumerable that exposes the keyed service key when appropriate.</returns>
41-
public static IEnumerable<Parameter> EnsureKeyedServiceParameter(object serviceKey, IEnumerable<Parameter> parameters)
38+
public static IEnumerable<Parameter> AddKeyedServiceParameter(object serviceKey, IEnumerable<Parameter> parameters)
4239
{
4340
if (serviceKey == null)
4441
{
@@ -50,19 +47,12 @@ public static IEnumerable<Parameter> EnsureKeyedServiceParameter(object serviceK
5047
throw new ArgumentNullException(nameof(parameters));
5148
}
5249

53-
if (KeyedService.IsAnyKey(serviceKey))
50+
if (KeyedService.IsAnyKey(serviceKey) || HasKeyParameter(parameters, serviceKey))
5451
{
5552
return parameters;
5653
}
5754

58-
if (parameters is IKeyedServiceKeyAccessor accessor &&
59-
accessor.TryGetServiceKey(out var existingKey) &&
60-
Equals(existingKey, serviceKey))
61-
{
62-
return parameters;
63-
}
64-
65-
return new KeyedServiceParameterCollection(parameters, serviceKey);
55+
return AppendKeyParameter(parameters, serviceKey);
6656
}
6757

6858
/// <summary>
@@ -72,72 +62,24 @@ public static IEnumerable<Parameter> EnsureKeyedServiceParameter(object serviceK
7262
/// <returns>A parameter capable of supplying the keyed service key, or null if not available.</returns>
7363
public static Parameter? TryCreateConstructorParameter(IEnumerable<Parameter> parameters)
7464
{
75-
if (parameters is IKeyedServiceKeyAccessor accessor &&
76-
accessor.TryGetServiceKey(out var key))
77-
{
78-
return new KeyedServiceConstructorParameter(key);
79-
}
80-
81-
return null;
65+
return parameters?
66+
.OfType<KeyedServiceKeyParameter>()
67+
.FirstOrDefault()?
68+
.ForConstructorInjection();
8269
}
8370

84-
/// <summary>
85-
/// Wraps a set of parameters with an associated keyed service key.
86-
/// </summary>
87-
private sealed class KeyedServiceParameterCollection : IEnumerable<Parameter>, IKeyedServiceKeyAccessor
88-
{
89-
private readonly IEnumerable<Parameter> _source;
90-
private readonly object _key;
91-
92-
public KeyedServiceParameterCollection(IEnumerable<Parameter> source, object key)
93-
{
94-
_source = source ?? throw new ArgumentNullException(nameof(source));
95-
_key = key ?? throw new ArgumentNullException(nameof(key));
96-
}
71+
private static bool HasKeyParameter(IEnumerable<Parameter> parameters, object serviceKey)
72+
=> parameters.OfType<KeyedServiceKeyParameter>().Any(p => Equals(p.ServiceKey, serviceKey));
9773

98-
public IEnumerator<Parameter> GetEnumerator() => _source.GetEnumerator();
99-
100-
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
101-
102-
public bool TryGetServiceKey([NotNullWhen(returnValue: true)] out object? key)
103-
{
104-
key = _key;
105-
return true;
106-
}
107-
}
108-
109-
/// <summary>
110-
/// Supplies the keyed service key value to constructor parameters when matching by type.
111-
/// </summary>
112-
private sealed class KeyedServiceConstructorParameter : Parameter
74+
private static IEnumerable<Parameter> AppendKeyParameter(IEnumerable<Parameter> parameters, object serviceKey)
11375
{
114-
private readonly object _key;
76+
var keyParameter = new KeyedServiceKeyParameter(serviceKey);
11577

116-
public KeyedServiceConstructorParameter(object key)
78+
if (ReferenceEquals(parameters, ResolveRequest.NoParameters))
11779
{
118-
_key = key ?? throw new ArgumentNullException(nameof(key));
80+
return new Parameter[] { keyParameter };
11981
}
12082

121-
public override bool CanSupplyValue(ParameterInfo pi, IComponentContext context, [NotNullWhen(returnValue: true)] out Func<object?>? valueProvider)
122-
{
123-
if (pi == null)
124-
{
125-
throw new ArgumentNullException(nameof(pi));
126-
}
127-
128-
if (context == null)
129-
{
130-
throw new ArgumentNullException(nameof(context));
131-
}
132-
133-
if (pi.ParameterType.IsAssignableFrom(_key.GetType()))
134-
{
135-
valueProvider = () => _key;
136-
return true;
137-
}
138-
139-
valueProvider = null;
140-
return false;
141-
}
83+
return parameters.Append(keyParameter);
14284
}
14385
}
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
// Copyright (c) Autofac Project. All rights reserved.
2+
// Licensed under the MIT License. See LICENSE in the project root for license information.
3+
4+
using System.Reflection;
5+
using Autofac.Core;
6+
7+
namespace Autofac;
8+
9+
/// <summary>
10+
/// Parameter that exposes the keyed service key for the current resolve operation.
11+
/// </summary>
12+
internal sealed class KeyedServiceKeyParameter : Parameter
13+
{
14+
private readonly bool _allowInjection;
15+
16+
/// <summary>
17+
/// Initializes a new instance of the <see cref="KeyedServiceKeyParameter"/> class.
18+
/// </summary>
19+
/// <param name="serviceKey">The keyed service key associated with the resolve operation.</param>
20+
/// <param name="allowInjection">Indicates whether this parameter may satisfy constructor arguments.</param>
21+
public KeyedServiceKeyParameter(object serviceKey, bool allowInjection = false)
22+
{
23+
ServiceKey = serviceKey ?? throw new ArgumentNullException(nameof(serviceKey));
24+
_allowInjection = allowInjection;
25+
}
26+
27+
/// <summary>
28+
/// Gets the keyed service key value.
29+
/// </summary>
30+
public object ServiceKey { get; }
31+
32+
/// <summary>
33+
/// Creates a copy of this parameter that can satisfy constructor arguments.
34+
/// </summary>
35+
/// <returns>A parameter instance capable of providing the keyed service value to constructors.</returns>
36+
public KeyedServiceKeyParameter ForConstructorInjection()
37+
=> _allowInjection ? this : new KeyedServiceKeyParameter(ServiceKey, allowInjection: true);
38+
39+
/// <inheritdoc />
40+
public override bool CanSupplyValue(ParameterInfo pi, IComponentContext context, [NotNullWhen(returnValue: true)] out Func<object?>? valueProvider)
41+
{
42+
if (pi == null)
43+
{
44+
throw new ArgumentNullException(nameof(pi));
45+
}
46+
47+
if (context == null)
48+
{
49+
throw new ArgumentNullException(nameof(context));
50+
}
51+
52+
if (_allowInjection && pi.ParameterType.IsInstanceOfType(ServiceKey))
53+
{
54+
valueProvider = () => ServiceKey;
55+
return true;
56+
}
57+
58+
valueProvider = null;
59+
return false;
60+
}
61+
}

src/Autofac/ParameterExtensions.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -103,10 +103,10 @@ public static T KeyedServiceKey<T>(this IEnumerable<Parameter> parameters)
103103
throw new ArgumentNullException(nameof(parameters));
104104
}
105105

106-
if (parameters is IKeyedServiceKeyAccessor accessor &&
107-
accessor.TryGetServiceKey(out var key))
106+
var keyParameter = parameters.OfType<KeyedServiceKeyParameter>().FirstOrDefault();
107+
if (keyParameter is not null)
108108
{
109-
return (T)key;
109+
return (T)keyParameter.ServiceKey;
110110
}
111111

112112
throw new InvalidOperationException(ResolutionExtensionsResources.KeyedServiceKeyUnavailable);

src/Autofac/ResolutionExtensions.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -418,7 +418,7 @@ public static TService ResolveKeyed<TService>(this IComponentContext context, ob
418418
where TService : notnull
419419
{
420420
EnsureAnyKeyUsageIsValid(serviceKey, typeof(TService));
421-
parameters = KeyedServiceParameterInjector.EnsureKeyedServiceParameter(serviceKey, parameters);
421+
parameters = KeyedServiceParameterInjector.AddKeyedServiceParameter(serviceKey, parameters);
422422
return CastInstance<TService>(ResolveService(context, new KeyedService(serviceKey, typeof(TService)), parameters));
423423
}
424424

@@ -483,7 +483,7 @@ public static object ResolveKeyed(this IComponentContext context, object service
483483
public static object ResolveKeyed(this IComponentContext context, object serviceKey, Type serviceType, IEnumerable<Parameter> parameters)
484484
{
485485
EnsureAnyKeyUsageIsValid(serviceKey, serviceType);
486-
parameters = KeyedServiceParameterInjector.EnsureKeyedServiceParameter(serviceKey, parameters);
486+
parameters = KeyedServiceParameterInjector.AddKeyedServiceParameter(serviceKey, parameters);
487487
return ResolveService(context, new KeyedService(serviceKey, serviceType), parameters);
488488
}
489489

@@ -1098,7 +1098,7 @@ public static bool TryResolveKeyed<T>(this IComponentContext context, object ser
10981098
public static bool TryResolveKeyed(this IComponentContext context, object serviceKey, Type serviceType, [NotNullWhen(returnValue: true)] out object? instance)
10991099
{
11001100
EnsureAnyKeyUsageIsValid(serviceKey, serviceType);
1101-
var parameters = KeyedServiceParameterInjector.EnsureKeyedServiceParameter(serviceKey, ResolveRequest.NoParameters);
1101+
var parameters = KeyedServiceParameterInjector.AddKeyedServiceParameter(serviceKey, ResolveRequest.NoParameters);
11021102
return context.TryResolveService(new KeyedService(serviceKey, serviceType), parameters, out instance);
11031103
}
11041104

test/Autofac.Test/Features/LightweightAdapters/LightweightAdapterRegistrationExtensionsTests.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -129,11 +129,11 @@ public void ParametersGoToTheDecoratedInstance()
129129
{
130130
var resolved = _container.Resolve<IParameterizedService>(TypedParameter.From<IService>(new Implementer1()));
131131
var dec2 = Assert.IsType<ParameterizedDecorator2>(resolved);
132-
Assert.Empty(dec2.Parameters);
132+
Assert.Empty(dec2.Parameters.OfType<TypedParameter>());
133133
var dec1 = Assert.IsType<ParameterizedDecorator1>(dec2.Implementer);
134-
Assert.Empty(dec1.Parameters);
134+
Assert.Empty(dec1.Parameters.OfType<TypedParameter>());
135135
var imp = Assert.IsType<ParameterizedImplementer>(dec1.Implementer);
136-
Assert.Single(imp.Parameters);
136+
Assert.Single(imp.Parameters.OfType<TypedParameter>());
137137
}
138138

139139
public interface IParameterizedService

0 commit comments

Comments
 (0)