LifetimeDescriptor
Represents a lifetime descriptor.
using Stashbox.Exceptions;
using Stashbox.Expressions;
using Stashbox.Registration;
using Stashbox.Resolution;
using System;
using System.Linq.Expressions;
using System.Runtime.CompilerServices;
namespace Stashbox.Lifetime
{
[System.Runtime.CompilerServices.NullableContext(1)]
[System.Runtime.CompilerServices.Nullable(0)]
public abstract class LifetimeDescriptor
{
private protected virtual bool StoreResultInLocalVariable => false;
protected virtual int LifeSpan => 0;
protected string Name { get; }
protected LifetimeDescriptor()
{
Name = GetType().Name;
}
[return: System.Runtime.CompilerServices.Nullable(2)]
internal Expression ApplyLifetime(ServiceRegistration serviceRegistration, ResolutionContext resolutionContext, TypeInformation typeInformation)
{
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(serviceRegistration, resolutionContext, typeInformation);
ParameterExpression orDefault = resolutionContext.DefinedVariables.GetOrDefault(serviceRegistration.RegistrationId);
if (orDefault != null)
return orDefault;
Expression expression = BuildLifetimeAppliedExpression(serviceRegistration, resolutionContext, typeInformation);
if (expression == null)
return null;
orDefault = typeInformation.Type.AsVariable(null);
if (typeInformation.Type != expression.Type)
expression = expression.ConvertTo(typeInformation.Type);
resolutionContext.AddDefinedVariable(serviceRegistration.RegistrationId, orDefault);
resolutionContext.AddInstruction(orDefault.AssignTo(expression));
return orDefault;
}
[return: System.Runtime.CompilerServices.Nullable(2)]
private protected abstract Expression BuildLifetimeAppliedExpression(ServiceRegistration serviceRegistration, ResolutionContext resolutionContext, TypeInformation typeInformation);
[return: System.Runtime.CompilerServices.Nullable(2)]
private protected static Expression GetExpressionForRegistration(ServiceRegistration serviceRegistration, ResolutionContext resolutionContext, TypeInformation typeInformation)
{
if (!IsRegistrationOutputCacheable(serviceRegistration, resolutionContext))
return ExpressionBuilder.BuildExpressionForRegistration(serviceRegistration, resolutionContext, typeInformation);
Expression orDefault = resolutionContext.ExpressionCache.GetOrDefault(serviceRegistration.RegistrationId);
if (orDefault != null)
return orDefault;
orDefault = ExpressionBuilder.BuildExpressionForRegistration(serviceRegistration, resolutionContext, typeInformation);
if (orDefault == null)
return null;
resolutionContext.CacheExpression(serviceRegistration.RegistrationId, orDefault);
return orDefault;
}
private protected static bool IsRegistrationOutputCacheable(ServiceRegistration serviceRegistration, ResolutionContext resolutionContext)
{
if (!serviceRegistration.IsDecorator && resolutionContext.RequestConfiguration.FactoryDelegateCacheEnabled && resolutionContext.PerResolutionRequestCacheEnabled)
return !(serviceRegistration is OpenGenericRegistration);
return false;
}
}
}