Skip to content

Commit

Permalink
fixed: #676
Browse files Browse the repository at this point in the history
  • Loading branch information
dadhi committed Feb 21, 2025
1 parent 683d6b1 commit 0b70866
Show file tree
Hide file tree
Showing 6 changed files with 58 additions and 32 deletions.
4 changes: 2 additions & 2 deletions bt.bat
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ setlocal EnableDelayedExpansion

rem Calculate start time
set started_at=%time%
set /a started_at_ms=%started_at:~0,2%*24*60*100+%started_at:~3,2%*60*100+%started_at:~6,2%*100+%started_at:~9,2%
set /a started_at_ms=1%started_at:~0,2%*24*60*100-100+%started_at:~3,2%*60*100+%started_at:~6,2%*100+%started_at:~9,2%

echo:
echo:# Build and Run TestRunner for .NET 9.0
Expand All @@ -15,7 +15,7 @@ if %ERRORLEVEL% neq 0 goto :error

rem Calculate elapsed time
set finished_at=%time%
set /a finished_at_ms=%finished_at:~0,2%*24*60*100+%finished_at:~3,2%*60*100+%finished_at:~6,2%*100+%finished_at:~9,2%
set /a finished_at_ms=1%finished_at:~0,2%*24*60*100-100+%finished_at:~3,2%*60*100+%finished_at:~6,2%*100+%finished_at:~9,2%
set /a ellapsed_ms=%finished_at_ms%*10-%started_at_ms%*10

echo:
Expand Down
17 changes: 13 additions & 4 deletions src/DryIoc.MefAttributedModel/AttributedModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1214,6 +1214,10 @@ public static class PrintCode
public static StringBuilder AppendBool(this StringBuilder code, bool x) =>
code.Append(x.ToCode());

/// <summary>Prints valid c# Boolean? literal: null/true/false.</summary>
public static StringBuilder AppendBool(this StringBuilder code, bool? x) =>
code.Append(x == null ? "null" : x.Value.ToCode());

/// <summary>Prints valid c# string constant.</summary>
public static StringBuilder AppendString(this StringBuilder code, string x) =>
code.Print(x);
Expand Down Expand Up @@ -1355,17 +1359,22 @@ public bool WeaklyReferenced
}

/// <summary>Allows registering transient disposable. But the disposal is up to you.</summary>
public bool AllowDisposableTransient
public bool? AllowDisposableTransient
{
get => (Flags & Setup.Settings.AllowDisposableTransient) != 0;
set => Flags = value ? Flags | Setup.Settings.AllowDisposableTransient : Flags & ~Setup.Settings.AllowDisposableTransient;
get => (Flags & Setup.Settings.ThrowOnRegisteringDisposableTransient) != 0 ? false
: (Flags & Setup.Settings.AllowDisposableTransient) != 0 ? true
: (bool?)null;
set => Flags = value == null ? Flags : value.Value ? Flags | Setup.Settings.AllowDisposableTransient
: Flags & ~Setup.Settings.AllowDisposableTransient & ~Setup.Settings.TrackDisposableTransient | Setup.Settings.ThrowOnRegisteringDisposableTransient;
}

/// <summary>Turns On tracking of disposable transient dependency in parent scope or in open scope if resolved directly.</summary>
public bool TrackDisposableTransient
{
get => (Flags & Setup.Settings.TrackDisposableTransient) != 0;
set => Flags = value ? Flags | Setup.Settings.TrackDisposableTransient : Flags & ~Setup.Settings.TrackDisposableTransient;
set => Flags = value
? Flags | Setup.Settings.TrackDisposableTransient | Setup.Settings.AllowDisposableTransient
: Flags & ~Setup.Settings.TrackDisposableTransient;
}

/// <summary>Instructs to use parent reuse. Applied only if Reuse is not specified.</summary>
Expand Down
36 changes: 20 additions & 16 deletions src/DryIoc/Container.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11397,6 +11397,9 @@ internal Setup WithAsResolutionCallForGeneratedExpression()
/// <summary>Stores reused instance as WeakReference.</summary>
public bool WeaklyReferenced => (_settings & Settings.WeaklyReferenced) != 0;

/// <summary>Disallows registration of the disposable transient.</summary>
public bool ThrowOnRegisteringDisposableTransient => (_settings & Settings.ThrowOnRegisteringDisposableTransient) != 0;

/// <summary>Allows registering transient disposable.</summary>
public bool AllowDisposableTransient => (_settings & Settings.AllowDisposableTransient) != 0;

Expand Down Expand Up @@ -11427,7 +11430,7 @@ private Setup() { }

private Setup(Func<Request, bool> condition,
bool openResolutionScope, bool asResolutionCall, bool asResolutionRoot, bool preventDisposal, bool weaklyReferenced,
Opt<bool> allowDisposableTransient, bool trackDisposableTransient, bool useParentReuse, int disposalOrder,
bool? allowDisposableTransient, bool trackDisposableTransient, bool useParentReuse, int disposalOrder,
bool preferOverMultipleResolved = false, bool asResolutionCallForExpressionGeneration = false,
bool avoidResolutionScopeTracking = false)
{
Expand All @@ -11452,8 +11455,7 @@ private Setup(Func<Request, bool> condition,
if (trackDisposableTransient)
{
// tracking means both to allow and track the transients
_settings |= Settings.TrackDisposableTransient;
_settings |= Settings.AllowDisposableTransient;
_settings |= Settings.TrackDisposableTransient | Settings.AllowDisposableTransient;
}

if (allowDisposableTransient.HasValue)
Expand All @@ -11464,8 +11466,8 @@ private Setup(Func<Request, bool> condition,
{
// if the value is provided and it is false, then we should not track the transients,
// nor allow to register transients at all
_settings &= ~Settings.TrackDisposableTransient;
_settings &= ~Settings.AllowDisposableTransient;
_settings &= ~Settings.TrackDisposableTransient;
_settings |= Settings.ThrowOnRegisteringDisposableTransient;
}
}
Expand Down Expand Up @@ -11515,7 +11517,7 @@ public static Setup With(
object metadataOrFuncOfMetadata = null, Func<Request, bool> condition = null,
bool openResolutionScope = false, bool asResolutionCall = false, bool asResolutionRoot = false,
bool preventDisposal = false, bool weaklyReferenced = false,
Opt<bool> allowDisposableTransient = default, bool trackDisposableTransient = false,
bool? allowDisposableTransient = default, bool trackDisposableTransient = false,
bool useParentReuse = false, int disposalOrder = 0, bool preferInSingleServiceResolve = false,
bool avoidResolutionScopeTracking = false)
{
Expand Down Expand Up @@ -11551,7 +11553,7 @@ public static Setup WrapperWith(int wrappedServiceTypeArgIndex = -1,
bool alwaysWrapsRequiredServiceType = false, Func<Type, Type> unwrap = null,
bool openResolutionScope = false, bool asResolutionCall = false,
bool preventDisposal = false, bool weaklyReferenced = false,
Opt<bool> allowDisposableTransient = default, bool trackDisposableTransient = false,
bool? allowDisposableTransient = default, bool trackDisposableTransient = false,
bool useParentReuse = false, Func<Request, bool> condition = null, int disposalOrder = 0,
bool avoidResolutionScopeTracking = false) =>
wrappedServiceTypeArgIndex == -1 && !alwaysWrapsRequiredServiceType && unwrap == null &&
Expand All @@ -11577,7 +11579,7 @@ public static Setup DecoratorWith(
Func<Request, bool> condition = null, int order = 0, bool useDecorateeReuse = false,
bool openResolutionScope = false, bool asResolutionCall = false,
bool preventDisposal = false, bool weaklyReferenced = false,
Opt<bool> allowDisposableTransient = default, bool trackDisposableTransient = false,
bool? allowDisposableTransient = default, bool trackDisposableTransient = false,
int disposalOrder = 0, bool avoidResolutionScopeTracking = false) =>
condition == null & order == 0 & !useDecorateeReuse & !openResolutionScope & !asResolutionCall &&
!preventDisposal & !weaklyReferenced & !allowDisposableTransient.HasValue & !trackDisposableTransient &
Expand All @@ -11603,7 +11605,7 @@ public static Func<Request, bool> GetDecorateeCondition(Type decorateeType, obje
/// <summary>Setup for decorator of type <paramref name="decorateeType"/>.</summary>
public static Setup DecoratorOf(Type decorateeType = null,
int order = 0, bool useDecorateeReuse = false, bool openResolutionScope = false, bool asResolutionCall = false,
bool preventDisposal = false, bool weaklyReferenced = false, Opt<bool> allowDisposableTransient = default,
bool preventDisposal = false, bool weaklyReferenced = false, bool? allowDisposableTransient = default,
bool trackDisposableTransient = false, int disposalOrder = 0, object decorateeServiceKey = null)
{
Func<Request, bool> cond = decorateeType == null & decorateeServiceKey == null
Expand All @@ -11620,7 +11622,7 @@ public static Setup DecoratorOf(Type decorateeType = null,
/// <summary>Setup for decorator of type <typeparamref name="TDecoratee"/>.</summary>
public static Setup DecoratorOf<TDecoratee>(
int order = 0, bool useDecorateeReuse = false, bool openResolutionScope = false, bool asResolutionCall = false,
bool preventDisposal = false, bool weaklyReferenced = false, Opt<bool> allowDisposableTransient = default,
bool preventDisposal = false, bool weaklyReferenced = false, bool? allowDisposableTransient = default,
bool trackDisposableTransient = false, int disposalOrder = 0, object decorateeServiceKey = null) =>
DecoratorOf(typeof(TDecoratee), order, useDecorateeReuse, openResolutionScope, asResolutionCall,
preventDisposal, weaklyReferenced, allowDisposableTransient, trackDisposableTransient,
Expand All @@ -11643,7 +11645,7 @@ public ServiceSetup() { }
/// Specify all the individual settings.
public ServiceSetup(Func<Request, bool> condition = null, object metadataOrFuncOfMetadata = null,
bool openResolutionScope = false, bool asResolutionCall = false, bool asResolutionRoot = false,
bool preventDisposal = false, bool weaklyReferenced = false, Opt<bool> allowDisposableTransient = default,
bool preventDisposal = false, bool weaklyReferenced = false, bool? allowDisposableTransient = default,
bool trackDisposableTransient = false, bool useParentReuse = false, int disposalOrder = 0,
bool preferOverMultipleResolved = false, bool asResolutionCallForExpressionGeneration = false,
bool avoidResolutionScopeTracking = false)
Expand Down Expand Up @@ -11687,7 +11689,7 @@ public WrapperSetup(int wrappedServiceTypeArgIndex = -1) =>
public WrapperSetup(int wrappedServiceTypeArgIndex, bool alwaysWrapsRequiredServiceType, Func<Type, Type> unwrap,
Func<Request, bool> condition,
bool openResolutionScope, bool asResolutionCall,
bool preventDisposal, bool weaklyReferenced, Opt<bool> allowDisposableTransient, bool trackDisposableTransient,
bool preventDisposal, bool weaklyReferenced, bool? allowDisposableTransient, bool trackDisposableTransient,
bool useParentReuse, int disposalOrder, bool avoidResolutionScopeTracking)
: base(condition, openResolutionScope, asResolutionCall, false, preventDisposal, weaklyReferenced,
allowDisposableTransient, trackDisposableTransient, useParentReuse, disposalOrder,
Expand Down Expand Up @@ -11759,7 +11761,7 @@ public DecoratorSetup() { }
public DecoratorSetup(Func<Request, bool> condition, int order, bool useDecorateeReuse,
bool openResolutionScope = false, bool asResolutionCall = false,
bool preventDisposal = false, bool weaklyReferenced = false,
Opt<bool> allowDisposableTransient = default, bool trackDisposableTransient = false,
bool? allowDisposableTransient = default, bool trackDisposableTransient = false,
int disposalOrder = 0, bool avoidResolutionScopeTracking = false)
: base(condition, openResolutionScope, asResolutionCall, false, preventDisposal, weaklyReferenced,
allowDisposableTransient, trackDisposableTransient, false, disposalOrder,
Expand Down Expand Up @@ -12101,13 +12103,14 @@ internal virtual bool ValidateAndNormalizeRegistration(Type serviceType, object
{
// Warn about registering disposable transient
var reuse = Reuse ?? rules.DefaultReuse;
if (reuse != DryIoc.Reuse.Transient || setup.AllowDisposableTransient || !rules.ThrowOnRegisteringDisposableTransient ||
if (reuse != DryIoc.Reuse.Transient || setup.AllowDisposableTransient ||
!(setup.ThrowOnRegisteringDisposableTransient || rules.ThrowOnRegisteringDisposableTransient) ||
setup.UseParentReuse)
return true;

var knownImplOrServiceType = CanAccessImplementationType ? ImplementationType : serviceType;
if (typeof(IDisposable).IsAssignableFrom(knownImplOrServiceType))
return Throw.When(throwIfInvalid, Error.RegisteredDisposableTransientWontBeDisposedByContainer, serviceType, serviceKey ?? "{no key}", this);
return Throw.When(throwIfInvalid, Error.RegisteredDisposableTransientWontBeDisposedByContainer, serviceType, serviceKey, this);
}
else if (setup.FactoryType == FactoryType.Wrapper)
{
Expand All @@ -12119,7 +12122,8 @@ internal virtual bool ValidateAndNormalizeRegistration(Type serviceType, object
return Throw.When(throwIfInvalid, Error.DecoratorShouldNotBeRegisteredWithServiceKey, serviceKey);

var reuse = Reuse ?? rules.DefaultReuse;
if (reuse != DryIoc.Reuse.Transient || setup.AllowDisposableTransient || !rules.ThrowOnRegisteringDisposableTransient ||
if (reuse != DryIoc.Reuse.Transient || setup.AllowDisposableTransient ||
!(setup.ThrowOnRegisteringDisposableTransient || rules.ThrowOnRegisteringDisposableTransient) ||
setup.UseDecorateeReuse)
return true;

Expand Down Expand Up @@ -15541,7 +15545,7 @@ protected static string GetMessage(ErrorCheck errorCheck, int errorCode) =>
errorCode == -1 ? Throw.GetDefaultMessage(errorCheck) : DryIoc.Error.Messages[errorCode];

/// <summary>Prints argument for formatted message.</summary> <param name="arg">To print.</param> <returns>Printed string.</returns>
protected static string Print(object arg) => arg == null ? string.Empty : arg.Print();
protected static string Print(object arg) => arg == null ? "{null}" : arg.Print();

/// <summary>Collects many exceptions.</summary>
public ContainerException(int error, ContainerException[] exceptions)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ public void Should_properly_print_registration_info_with_Singleton_reuse_type()
AsResolutionRoot = false,
PreventDisposal = false,
WeaklyReferenced = false,
AllowDisposableTransient = false,
AllowDisposableTransient = null,
TrackDisposableTransient = false,
UseParentReuse = false,
HasMetadataAttribute = false,
Expand Down Expand Up @@ -62,7 +62,7 @@ public void Should_properly_print_registration_info_with_default_reuse_type()
AsResolutionRoot = false,
PreventDisposal = false,
WeaklyReferenced = false,
AllowDisposableTransient = false,
AllowDisposableTransient = null,
TrackDisposableTransient = false,
UseParentReuse = false,
HasMetadataAttribute = false,
Expand Down
2 changes: 1 addition & 1 deletion test/DryIoc.TestRunner/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ public class Program
{
public static void Main()
{
new RulesTests().Run();
// new RulesTests().Run();

// new GHIssue672_Wrong_decorator_parameter_with_custom_args().Run();

Expand Down
27 changes: 20 additions & 7 deletions test/DryIoc.UnitTests/RulesTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,7 @@ public class RulesTests : ITest
{
public int Run()
{
// @wip
I_can_override_global_disposable_transient_tracking_and_prohibit_its_registration();
I_can_override_global_disposable_transient_allowance_and_prohibit_its_registration_despite_local_setting();

Given_service_with_two_ctors_I_can_specify_what_ctor_to_choose_for_resolve();
I_should_be_able_to_add_rule_to_resolve_not_registered_service();
Expand Down Expand Up @@ -45,6 +44,7 @@ public int Run()
Should_track_transient_disposable_service_in_singleton_scope();
I_can_override_global_disposable_transient_tracking_for_the_registration();
I_can_override_global_disposable_transient_tracking_and_prohibit_its_registration();
I_can_override_global_disposable_transient_allowance_and_prohibit_its_registration_despite_local_setting();
Should_not_track_func_of_transient_disposable_dependency_in_singleton_scope();
Should_track_lazy_of_transient_disposable_dependency_in_singleton_scope();
Should_track_transient_disposable_dependency_in_current_scope();
Expand All @@ -58,7 +58,7 @@ public int Run()
If_IfAlreadyRegistered_per_Container_affects_RegisterMany_as_expected();
Can_specify_to_capture_stack_trace_and_display_it_disposed_exception();
DisposedContainer_error_message_should_include_tip_how_to_enable_stack_trace();
return 41;
return 42;
}

[Test]
Expand Down Expand Up @@ -506,18 +506,31 @@ public void I_can_override_global_disposable_transient_tracking_for_the_registra
Assert.IsFalse(anyTracked);
}

// [Test] // todo: @wip
[Test]
public void I_can_override_global_disposable_transient_tracking_and_prohibit_its_registration()
{
using var container = new Container(Rules.Default.WithTrackingDisposableTransients());

// Does it even make sense to register disposable transient and at the same time prohibit its resgitrations.
// Does it even make sense to register disposable transient and at the same time prohibit its registrations?
// I think the only valid case for this is when you don't know that the registred service is IDisposable,
// or if it is changed over the course of the program development.
// Or if it is set in some integration scenario, for instance when we read those individual registration settings from
// the attribute.
Assert.DoesNotThrow(() =>
container.Register<AD>(setup: Setup.With(allowDisposableTransient: false, trackDisposableTransient: false)));
var ex = Assert.Throws<ContainerException>(() =>
container.Register<AD>(setup: Setup.With(allowDisposableTransient: false)));

Assert.AreEqual(Error.NameOf(Error.RegisteredDisposableTransientWontBeDisposedByContainer), ex.ErrorName);
}

[Test]
public void I_can_override_global_disposable_transient_allowance_and_prohibit_its_registration_despite_local_setting()
{
using var container = new Container(Rules.Default.WithoutThrowOnRegisteringDisposableTransient());

var ex = Assert.Throws<ContainerException>(() =>
container.Register<AD>(setup: Setup.With(allowDisposableTransient: false, trackDisposableTransient: true)));

Assert.AreEqual(Error.NameOf(Error.RegisteredDisposableTransientWontBeDisposedByContainer), ex.ErrorName);
}

[Test]
Expand Down

0 comments on commit 0b70866

Please sign in to comment.