diff --git a/src/DryIoc/Container.cs b/src/DryIoc/Container.cs
index 96542ac66..4470fd2ac 100644
--- a/src/DryIoc/Container.cs
+++ b/src/DryIoc/Container.cs
@@ -13661,6 +13661,21 @@ public interface IScopeName
bool Match(object scopeName);
}
+ /// Custom name matcher via the provided function.
+ /// It may be used as a negative check, e.g. to avoid cirtain scopes and proceed to search for the specific parent scope.
+ public sealed class ScopeName : IScopeName
+ {
+ /// Constucts the scope name matches based on the user-provided predicate
+ public static ScopeName Of(Func matchPredicate) => new ScopeName(matchPredicate);
+
+ /// The match precicate
+ public readonly Func MatchPredicate;
+ private ScopeName(Func matchPredicate) => MatchPredicate = matchPredicate;
+
+ ///
+ public bool Match(object scopeName) => MatchPredicate(scopeName);
+ }
+
/// Represents multiple names
public sealed class CompositeScopeName : IScopeName
{
@@ -13714,16 +13729,11 @@ private ResolutionScopeName(Type serviceType, object serviceKey)
}
///
- public bool Match(object scopeName)
- {
- var name = scopeName as ResolutionScopeName;
- return name != null &&
- (ServiceType == null ||
- name.ServiceType.IsAssignableTo(ServiceType) ||
- ServiceType.IsOpenGeneric() &&
- name.ServiceType.GetGenericDefinitionOrNull().IsAssignableTo(ServiceType)) &&
- (ServiceKey == null || ServiceKey.Equals(name.ServiceKey));
- }
+ public bool Match(object scopeName) =>
+ scopeName is ResolutionScopeName name &&
+ (ServiceType == null || name.ServiceType.IsAssignableTo(ServiceType) ||
+ ServiceType.IsOpenGeneric() && name.ServiceType.GetGenericDefinitionOrNull().IsAssignableTo(ServiceType)) &&
+ (ServiceKey == null || ServiceKey.Equals(name.ServiceKey));
/// String representation for easy debugging and understood error messages.
public override string ToString()
diff --git a/test/DryIoc.IssuesTests/GHIssue565_Is_ignoring_ReuseScoped_setting_expected_behaviour_when_also_set_to_openResolutionScope.cs b/test/DryIoc.IssuesTests/GHIssue565_Is_ignoring_ReuseScoped_setting_expected_behaviour_when_also_set_to_openResolutionScope.cs
index a9767e4df..b2108289f 100644
--- a/test/DryIoc.IssuesTests/GHIssue565_Is_ignoring_ReuseScoped_setting_expected_behaviour_when_also_set_to_openResolutionScope.cs
+++ b/test/DryIoc.IssuesTests/GHIssue565_Is_ignoring_ReuseScoped_setting_expected_behaviour_when_also_set_to_openResolutionScope.cs
@@ -10,8 +10,9 @@ public int Run()
{
TestScope_Zero();
TestScope_One();
+ TestScope_One_WithScopeNameOf();
TestScope_Two();
- return 3;
+ return 4;
}
[Test]
@@ -61,10 +62,10 @@ public void TestScope_Zero()
});
}
- public sealed class ToAnyScopeExceptResolutionScopeOf : IScopeName
+ public sealed class AnyScopeExceptResolutionScopeOf : IScopeName
{
- public static readonly IScopeName Instance = new ToAnyScopeExceptResolutionScopeOf();
- private ToAnyScopeExceptResolutionScopeOf() {}
+ public static readonly IScopeName Instance = new AnyScopeExceptResolutionScopeOf();
+ private AnyScopeExceptResolutionScopeOf() {}
public bool Match(object scopeName) =>
scopeName is not ResolutionScopeName rn || rn.ServiceType != typeof(T);
}
@@ -78,7 +79,61 @@ public void TestScope_One()
/// even though it has opened a new scope internally.
var container = new Container();
container.Register(setup: Setup.With(openResolutionScope: true), reuse: Reuse.Transient);
- container.Register(setup: Setup.With(openResolutionScope: true), reuse: Reuse.ScopedTo(ToAnyScopeExceptResolutionScopeOf.Instance));
+ container.Register(setup: Setup.With(openResolutionScope: true), reuse: Reuse.ScopedTo(AnyScopeExceptResolutionScopeOf.Instance));
+ container.Register(Reuse.Singleton);
+ container.Resolve().GetId();
+ var car = container.Resolve();
+ // Get guid id for each class and guid store array
+ var iCarId = (nameof(ICar), car.GetId());
+ var iBarId = (nameof(IBar), car.GetBarId());
+ var iFooId = (nameof(IFoo), car.GetFooId());
+ var IdArray = car.GetIdArray();
+ Assert.Multiple(() =>
+ {
+ // Assert that each name id pair matches with that stored
+ // in the first three elements of the array
+ Assert.That(IdArray[0], Is.EqualTo(iCarId));
+ Assert.That(IdArray[1], Is.EqualTo(iBarId));
+ Assert.That(IdArray[2], Is.EqualTo(iFooId));
+ // Assert that each name id pair matches with each again.
+ // IBar and IFoo have been resolved from container in ICar class.
+ // IBar should be the same: Fail!!
+ Assert.That(IdArray[3], Is.EqualTo(iCarId));
+ Assert.That(IdArray[4], Is.EqualTo(iBarId));
+ Assert.That(IdArray[5], Is.EqualTo(iFooId));
+ // New Scope is opened in ICar. Check if ICar and IFoo is the Same
+ // but IBar should be new ID.
+ Assert.That(IdArray[6], Is.EqualTo(iCarId));
+ Assert.That(IdArray[7], !Is.EqualTo(iBarId));
+ Assert.That(IdArray[8], Is.EqualTo(iFooId));
+ // Assert that each name id pair matches with each again.
+ // IBar should still be new ID. but should resolve twice
+ // and be the same as the id from Array index 7 : Fail!!
+ Assert.That(IdArray[9], Is.EqualTo(iCarId));
+ Assert.That(IdArray[10], !Is.EqualTo(iBarId));
+ Assert.That(IdArray[10], Is.EqualTo(IdArray[7]));
+ Assert.That(IdArray[11], Is.EqualTo(iFooId));
+ // Assert that each name id pair matches with each again.
+ // IBar Should match the original Ibar Id. Fail!!
+ Assert.That(IdArray[12], Is.EqualTo(iCarId));
+ Assert.That(IdArray[13], Is.EqualTo(iBarId));
+ Assert.That(IdArray[14], Is.EqualTo(iFooId));
+ });
+ }
+
+ [Test]
+ public void TestScope_One_WithScopeNameOf()
+ {
+ /// This Test Fails when IBar is registered with openResolutionScope: true.
+ /// When iBar is Resolved it is resolved with a new instance each time.
+ /// My expectation is that is is still scoped to which ever scope it was resolved to
+ /// even though it has opened a new scope internally.
+ var container = new Container();
+ container.Register(setup: Setup.With(openResolutionScope: true), reuse: Reuse.Transient);
+
+ var anyScopeExceptBar = ScopeName.Of(n => n is not ResolutionScopeName rn || rn.ServiceType != typeof(IBar));
+ container.Register(setup: Setup.With(openResolutionScope: true), reuse: Reuse.ScopedTo(anyScopeExceptBar));
+
container.Register(Reuse.Singleton);
container.Resolve().GetId();
var car = container.Resolve();