diff --git a/src/DryIoc/Container.cs b/src/DryIoc/Container.cs index a3312a4ee..931d89fe8 100644 --- a/src/DryIoc/Container.cs +++ b/src/DryIoc/Container.cs @@ -764,7 +764,7 @@ public IResolverContext WithCurrentScope(IScope scope) registry.DropFactoryCache(oldFactory, serviceType); else ((FactoriesEntry)oldEntry).Factories.Enumerate().ToArray() - .DoPer(x => registry.DropFactoryCache(x.Value, serviceType, serviceKey)); + .ForEach(x => registry.DropFactoryCache(x.Value, serviceType, serviceKey)); } return registry; @@ -1266,11 +1266,22 @@ Expression IContainer.GetDecoratorExpressionOrDefault(Request request) { appliedDecoratorIDs = appliedDecoratorIDs ?? GetAppliedDecoratorIDs(request); if (!appliedDecoratorIDs.IsNullOrEmpty()) + { genericDecorators = genericDecorators .Match(appliedDecoratorIDs, - (ids, d) => d.FactoryGenerator == null - ? ids.IndexOf(d.FactoryID) == -1 - : d.FactoryGenerator.GeneratedFactories.Enumerate().All(f => ids.IndexOf(f.Value.FactoryID) == -1)); + (appliedDecIds, d) => + { + var factoryGenerator = d.FactoryGenerator; + if (factoryGenerator == null) + return appliedDecIds.IndexOf(d.FactoryID) == -1; + + foreach (var entry in factoryGenerator.GeneratedFactories.Enumerate()) + if (appliedDecIds.IndexOf(entry.Value.FactoryID) != -1) + return false; + + return true; + }); + } // Generate closed-generic versions if (!genericDecorators.IsNullOrEmpty()) @@ -1423,7 +1434,7 @@ public Expression GetConstantExpression(object item, Type itemType = null, bool Error.StateIsRequiredToUseItem, item); return itemType == null ? Constant(item) : Constant(item, itemType); - } + }l private static readonly MethodInfo _kvOfMethod = typeof(KV).GetTypeInfo().GetDeclaredMethod(nameof(KV.Of)); @@ -2130,7 +2141,7 @@ private Registry UnregisterServiceFactory(Type serviceType, object serviceKey = else (removed as Factory[] ?? ((FactoriesEntry)removed).Factories.Enumerate().Select(f => f.Value).ToArray()) - .DoPer(x => registry.DropFactoryCache(x, serviceType, serviceKey)); + .ForEach(x => registry.DropFactoryCache(x, serviceType, serviceKey)); return registry; } @@ -8566,10 +8577,14 @@ public Factory GetGeneratedFactory(Request request, bool ifErrorReturnDefault = var closedGenericFactory = new ReflectionFactory(implType, openFactory.Reuse, made, openFactory.Setup) { - Caching = openFactory.Caching, - GeneratorFactoryID = openFactory.FactoryID + GeneratorFactoryID = openFactory.FactoryID, + Caching = openFactory.Caching }; - _generatedFactories.AddOrUpdate(generatedFactoryKey, closedGenericFactory); + + // we should use whatever the first factory is registered because it can be used already in decorators and recursive factories check + _generatedFactories.Swap(generatedFactoryKey, closedGenericFactory, + (genFacKey, fac, facs) => facs.AddOrUpdate(genFacKey, fac, (oldFac, _) => closedGenericFactory = oldFac)); + return closedGenericFactory; } @@ -10651,7 +10666,7 @@ internal static class RefMap Ref.Swap(ref map, x => x.AddOrUpdate(key, value)); public static void AddOrUpdate(this Ref> map, K key, V value) => - map.Swap(key, value, (m, k, v) => m.AddOrUpdate(k, v)); + map.Swap(key, value, (k, v, m) => m.AddOrUpdate(k, v)); public static void AddOrUpdate(ref ImHashMap map, K key, V value) => Ref.Swap(ref map, x => x.AddOrUpdate(key, value)); diff --git a/src/DryIoc/ImTools.cs b/src/DryIoc/ImTools.cs index eab67550b..d1b3fa90f 100644 --- a/src/DryIoc/ImTools.cs +++ b/src/DryIoc/ImTools.cs @@ -256,14 +256,12 @@ public static T SingleOrDefaultIfMany(this IEnumerable source) if (!e.MoveNext()) return default(T); var it = e.Current; - if (!e.MoveNext()) - return it; - return default(T); + return !e.MoveNext() ? it : default(T); } } /// Does for each item - public static void DoPer(this T[] source, Action action) + public static void ForEach(this T[] source, Action action) { if (!source.IsNullOrEmpty()) for (var i = 0; i < source.Length; i++) @@ -635,10 +633,10 @@ public Ref(T initialValue = default(T)) public T Swap(Func getNewValue) => Ref.Swap(ref _value, getNewValue); /// Option without allocation for capturing `a` in closure of `getNewValue` - public T Swap(A a, Func getNewValue) => Ref.Swap(ref _value, a, getNewValue); + public T Swap(A a, Func getNewValue) => Ref.Swap(ref _value, a, getNewValue); /// Option without allocation for capturing `a` and `b` in closure of `getNewValue` - public T Swap(A a, B b, Func getNewValue) => Ref.Swap(ref _value, a, b, getNewValue); + public T Swap(A a, B b, Func getNewValue) => Ref.Swap(ref _value, a, b, getNewValue); /// Just sets new value ignoring any intermingled changes. /// old value @@ -695,13 +693,13 @@ public static class Ref } /// Option without allocation for capturing `a` in closure of `getNewValue` - public static T Swap(ref T value, A a, Func getNewValue) where T : class + public static T Swap(ref T value, A a, Func getNewValue) where T : class { var retryCount = 0; while (true) { var oldValue = value; - var newValue = getNewValue(oldValue, a); + var newValue = getNewValue(a, oldValue); if (Interlocked.CompareExchange(ref value, newValue, oldValue) == oldValue) return oldValue; if (++retryCount > RETRY_COUNT_UNTIL_THROW) @@ -710,13 +708,13 @@ public static class Ref } /// Option without allocation for capturing `a` and `b` in closure of `getNewValue` - public static T Swap(ref T value, A a, B b, Func getNewValue) where T : class + public static T Swap(ref T value, A a, B b, Func getNewValue) where T : class { var retryCount = 0; while (true) { var oldValue = value; - var newValue = getNewValue(oldValue, a, b); + var newValue = getNewValue(a, b, oldValue); if (Interlocked.CompareExchange(ref value, newValue, oldValue) == oldValue) return oldValue; if (++retryCount > RETRY_COUNT_UNTIL_THROW) @@ -731,7 +729,7 @@ public static class Ref " times But there is always someone else intervened."; } - /// Printable thingy via provided printer + /// Printable string via provided printer public interface IPrintable { /// Print to the provided string builder via the provided printer. diff --git a/test/DryIoc.IssuesTests/GHIssue116_DryIoc_Resolve_with_decorators_goes_wrong_for_parallel_execution.cs b/test/DryIoc.IssuesTests/GHIssue116_DryIoc_Resolve_with_decorators_goes_wrong_for_parallel_execution.cs index 1489f36bb..b3aa8e0da 100644 --- a/test/DryIoc.IssuesTests/GHIssue116_DryIoc_Resolve_with_decorators_goes_wrong_for_parallel_execution.cs +++ b/test/DryIoc.IssuesTests/GHIssue116_DryIoc_Resolve_with_decorators_goes_wrong_for_parallel_execution.cs @@ -8,7 +8,7 @@ namespace DryIoc.IssuesTests [TestFixture] public class GHIssue116_DryIoc_Resolve_with_decorators_goes_wrong_for_parallel_execution { - [Test][Ignore("fixme")] + [Test] public async Task DryIoc_Resolve_parallel_execution() { var container = new Container(); diff --git a/test/DryIoc.IssuesTests/GHIssue80_ScopedOrSingleton_extra_constructor_calls.cs b/test/DryIoc.IssuesTests/GHIssue80_ScopedOrSingleton_extra_constructor_calls.cs index fa99a9932..ce3a6db2d 100644 --- a/test/DryIoc.IssuesTests/GHIssue80_ScopedOrSingleton_extra_constructor_calls.cs +++ b/test/DryIoc.IssuesTests/GHIssue80_ScopedOrSingleton_extra_constructor_calls.cs @@ -117,9 +117,6 @@ public static void Log(string s) Debug.WriteLine(s); } - public static string String() - { - return string.Join("\r\n", Lines); - } + public static string String() => string.Join("\r\n", Lines); } }