LifetimeDescriptor
Represents a lifetime descriptor.
using Stashbox.Exceptions;
using Stashbox.Expressions;
using Stashbox.Registration;
using Stashbox.Resolution;
using System;
using System.Linq.Expressions;
namespace Stashbox.Lifetime
{
public abstract class LifetimeDescriptor
{
private protected virtual bool StoreResultInLocalVariable { get; }
protected virtual int LifeSpan { get; }
protected string Name { get; }
protected LifetimeDescriptor()
{
Name = GetType().Name;
}
internal Expression ApplyLifetime(ExpressionBuilder expressionBuilder, ServiceRegistration serviceRegistration, ResolutionContext resolutionContext, Type requestedType)
{
if (resolutionContext.CurrentContainerContext.ContainerConfiguration.LifetimeValidationEnabled && LifeSpan > 0) {
if (resolutionContext.CurrentLifeSpan > LifeSpan)
throw new LifetimeValidationFailedException(serviceRegistration.ImplementationType, $"""{serviceRegistration.ImplementationType}""{Name}""{LifeSpan}""" + "is shorter than its direct or indirect parent's " + resolutionContext.NameOfServiceLifeSpanValidatingAgainst + "." + Environment.NewLine + "This could lead to incidental lifetime promotions with longer life-span, it's recommended to double check your lifetime configurations.");
resolutionContext = resolutionContext.BeginLifetimeValidationContext(LifeSpan, $"{serviceRegistration.ImplementationType}""{Name}""{LifeSpan}""");
}
if (!StoreResultInLocalVariable)
return BuildLifetimeAppliedExpression(expressionBuilder, serviceRegistration, resolutionContext, requestedType);
ParameterExpression knownVariableOrDefault = resolutionContext.GetKnownVariableOrDefault(serviceRegistration.RegistrationId);
if (knownVariableOrDefault != null)
return knownVariableOrDefault;
Expression expression = BuildLifetimeAppliedExpression(expressionBuilder, serviceRegistration, resolutionContext, requestedType);
if (expression == null)
return null;
knownVariableOrDefault = requestedType.AsVariable(null);
resolutionContext.AddDefinedVariable(serviceRegistration.RegistrationId, knownVariableOrDefault);
resolutionContext.AddInstruction(knownVariableOrDefault.AssignTo(expression));
return knownVariableOrDefault;
}
private protected abstract Expression BuildLifetimeAppliedExpression(ExpressionBuilder expressionBuilder, ServiceRegistration serviceRegistration, ResolutionContext resolutionContext, Type requestedType);
private protected static Expression GetExpressionForRegistration(ExpressionBuilder expressionBuilder, ServiceRegistration serviceRegistration, ResolutionContext resolutionContext, Type requestedType)
{
if (!IsRegistrationOutputCacheable(serviceRegistration, resolutionContext))
return expressionBuilder.BuildExpressionForRegistration(serviceRegistration, resolutionContext, requestedType);
Expression cachedExpression = resolutionContext.GetCachedExpression(serviceRegistration.RegistrationId);
if (cachedExpression != null)
return cachedExpression;
cachedExpression = expressionBuilder.BuildExpressionForRegistration(serviceRegistration, resolutionContext, requestedType);
resolutionContext.CacheExpression(serviceRegistration.RegistrationId, cachedExpression);
return cachedExpression;
}
private protected static bool IsRegistrationOutputCacheable(ServiceRegistration serviceRegistration, ResolutionContext resolutionContext)
{
if (!serviceRegistration.IsDecorator && resolutionContext.FactoryDelegateCacheEnabled && resolutionContext.PerResolutionRequestCacheEnabled)
return serviceRegistration.RegistrationType != RegistrationType.OpenGeneric;
return false;
}
}
}