Skip to content

Commit

Permalink
Minor tweaks to lifetime selector feature
Browse files Browse the repository at this point in the history
  • Loading branch information
khellang committed Dec 23, 2024
1 parent 0b1d216 commit 4284819
Show file tree
Hide file tree
Showing 5 changed files with 32 additions and 22 deletions.
4 changes: 2 additions & 2 deletions src/Scrutor/ILifetimeSelector.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ public interface ILifetimeSelector : IServiceTypeSelector
IImplementationTypeSelector WithLifetime(ServiceLifetime lifetime);

/// <summary>
/// Registers each matching concrete type with the specified <paramref name="lifetime"/>.
/// Registers each matching concrete type with a lifetime based on the provided <paramref name="selector"/>.
/// </summary>
IImplementationTypeSelector WithLifetime(Func<Type, ServiceLifetime> lifetime);
IImplementationTypeSelector WithLifetime(Func<Type, ServiceLifetime> selector);
}
33 changes: 22 additions & 11 deletions src/Scrutor/LifetimeSelector.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ public LifetimeSelector(ServiceTypeSelector inner, IEnumerable<TypeMap> typeMaps

private IEnumerable<TypeFactoryMap> TypeFactoryMaps { get; }

public Func<Type, ServiceLifetime>? Lifetime { get; set; }
public Func<Type, ServiceLifetime>? SelectorFn { get; set; }

public IImplementationTypeSelector WithSingletonLifetime()
{
Expand All @@ -44,11 +44,11 @@ public IImplementationTypeSelector WithLifetime(ServiceLifetime lifetime)
return WithLifetime(_ => lifetime);
}

public IImplementationTypeSelector WithLifetime(Func<Type, ServiceLifetime> lifetime)
public IImplementationTypeSelector WithLifetime(Func<Type, ServiceLifetime> selector)
{
Preconditions.NotNull(lifetime, nameof(lifetime));
Preconditions.NotNull(selector, nameof(selector));

Inner.PropagateLifetime(lifetime);
Inner.PropagateLifetime(selector);

return this;
}
Expand Down Expand Up @@ -211,7 +211,7 @@ void ISelector.Populate(IServiceCollection services, RegistrationStrategy? strat
{
strategy ??= RegistrationStrategy.Append;

var serviceLifetimes = new Dictionary<Type, ServiceLifetime>();
var lifetimes = new Dictionary<Type, ServiceLifetime>();

foreach (var typeMap in TypeMaps)
{
Expand All @@ -224,7 +224,9 @@ void ISelector.Populate(IServiceCollection services, RegistrationStrategy? strat
throw new InvalidOperationException($@"Type ""{implementationType.ToFriendlyName()}"" is not assignable to ""${serviceType.ToFriendlyName()}"".");
}

var descriptor = new ServiceDescriptor(serviceType, implementationType, GetOrAddLifetime(serviceLifetimes, implementationType));
var lifetime = GetOrAddLifetime(lifetimes, implementationType);

var descriptor = new ServiceDescriptor(serviceType, implementationType, lifetime);

strategy.Apply(services, descriptor);
}
Expand All @@ -234,17 +236,26 @@ void ISelector.Populate(IServiceCollection services, RegistrationStrategy? strat
{
foreach (var serviceType in typeFactoryMap.ServiceTypes)
{
var descriptor = new ServiceDescriptor(serviceType, typeFactoryMap.ImplementationFactory, GetOrAddLifetime(serviceLifetimes, typeFactoryMap.ImplementationType));
var lifetime = GetOrAddLifetime(lifetimes, typeFactoryMap.ImplementationType);

var descriptor = new ServiceDescriptor(serviceType, typeFactoryMap.ImplementationFactory, lifetime);

strategy.Apply(services, descriptor);
}
}
}

private ServiceLifetime GetOrAddLifetime(Dictionary<Type, ServiceLifetime> serviceLifetimes, Type implementationType)
private ServiceLifetime GetOrAddLifetime(Dictionary<Type, ServiceLifetime> lifetimes, Type implementationType)
{
return serviceLifetimes.TryGetValue(implementationType, out var lifetime)
? lifetime
: (serviceLifetimes[implementationType] = Lifetime?.Invoke(implementationType) ?? ServiceLifetime.Transient);
if (lifetimes.TryGetValue(implementationType, out var lifetime))
{
return lifetime;
}

lifetime = SelectorFn?.Invoke(implementationType) ?? ServiceLifetime.Transient;

lifetimes[implementationType] = lifetime;

return lifetime;
}
}
2 changes: 1 addition & 1 deletion src/Scrutor/ServiceCollectionExtensions.Decoration.cs
Original file line number Diff line number Diff line change
Expand Up @@ -281,7 +281,7 @@ public static bool TryDecorate(this IServiceCollection services, DecorationStrat
/// <param name="descriptor">The service descriptor.</param>
public static bool IsDecorated(this ServiceDescriptor descriptor) =>
descriptor.ServiceKey is string stringKey
&& stringKey.EndsWith(DecoratedServiceKeySuffix, StringComparison.Ordinal);
&& stringKey.EndsWith(DecoratedServiceKeySuffix, StringComparison.Ordinal);

private static string? GetDecoratorKey(ServiceDescriptor descriptor)
{
Expand Down
6 changes: 3 additions & 3 deletions src/Scrutor/ServiceTypeSelector.cs
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ public ILifetimeSelector AsSelfWithInterfaces(Func<Type, bool> predicate)

return AddSelector(
Types.Select(t => new TypeMap(t, new[] { t })),
Types.Select(t => new TypeFactoryMap(x => x.GetRequiredService(t), Selector(t, predicate), t)));
Types.Select(t => new TypeFactoryMap(t, x => x.GetRequiredService(t), Selector(t, predicate))));

static IEnumerable<Type> Selector(Type type, Func<Type, bool> predicate)
{
Expand Down Expand Up @@ -209,11 +209,11 @@ public IServiceTypeSelector AddClasses(Action<IImplementationTypeFilter> action,

#endregion

internal void PropagateLifetime(Func<Type, ServiceLifetime> lifetime)
internal void PropagateLifetime(Func<Type, ServiceLifetime> selectorFn)
{
foreach (var selector in Selectors.OfType<LifetimeSelector>())
{
selector.Lifetime = lifetime;
selector.SelectorFn = selectorFn;
}
}

Expand Down
9 changes: 4 additions & 5 deletions src/Scrutor/TypeFactoryMap.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,16 @@ namespace Scrutor;

internal struct TypeFactoryMap
{
public TypeFactoryMap(Func<IServiceProvider, object> implementationFactory, IEnumerable<Type> serviceTypes, Type implementationType)
public TypeFactoryMap(Type implementationType, Func<IServiceProvider, object> implementationFactory, IEnumerable<Type> serviceTypes)
{
ImplementationType = implementationType;
ImplementationFactory = implementationFactory;
ServiceTypes = serviceTypes;
ImplementationType = implementationType;
}

public Type ImplementationType { get; }

public Func<IServiceProvider, object> ImplementationFactory { get; }

public IEnumerable<Type> ServiceTypes { get; }

public Type ImplementationType { get; }

}

0 comments on commit 4284819

Please sign in to comment.