diff --git a/.vscode/settings.json b/.vscode/settings.json index 6d2d608d9..06451f8e1 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,5 +1,8 @@ { "cSpell.words": [ "decoratee" - ] + ], + "files.watcherExclude": { + "**/target": true + } } \ No newline at end of file diff --git a/src/DryIoc.MefAttributedModel/AttributedModel.cs b/src/DryIoc.MefAttributedModel/AttributedModel.cs index 1addb2dca..420ab972f 100644 --- a/src/DryIoc.MefAttributedModel/AttributedModel.cs +++ b/src/DryIoc.MefAttributedModel/AttributedModel.cs @@ -100,26 +100,24 @@ public static IContainer WithMefAttributedModel(this IContainer container) => /// The container with made registration. public static IContainer WithImportsSatisfiedNotification(this IContainer container) { - container.Register( - made: _importsSatisfiedNotificationFactoryMethod, - setup: _importsSatisfiedNotificationDecoratorSetup); + var made = Made.Of(typeof(AttributedModel).SingleMethod(nameof(NotifyImportsSatisfied), includeNonPublic: true)); + + var decoratorSetup = Setup.DecoratorWith( + r => r.GetKnownImplementationOrServiceType().IsAssignableTo(), // todo: @perf can we filter it without registering the `object` decorator + order: int.MinValue, // Important, sets the decorator as a first one, so it will always being called + useDecorateeReuse: true); + + container.Register(made: made, setup: decoratorSetup); + return container; } internal static TService NotifyImportsSatisfied(TService service) { - (service as IPartImportsSatisfiedNotification)?.OnImportsSatisfied(); + ((IPartImportsSatisfiedNotification)service).OnImportsSatisfied(); return service; } - private static readonly Made _importsSatisfiedNotificationFactoryMethod = Made.Of( - typeof(AttributedModel).SingleMethod(nameof(NotifyImportsSatisfied), includeNonPublic: true)); - - private static readonly Setup _importsSatisfiedNotificationDecoratorSetup = Setup.DecoratorWith( - r => r.GetKnownImplementationOrServiceType().IsAssignableTo(), - order: int.MinValue, // Important, sets the decorator as a first one, so it will always being called - useDecorateeReuse: true); - #endregion #region ExportFactory, ExportFactory and Lazy support @@ -248,31 +246,29 @@ public static IContainer WithMultipleSameContractNamesSupport(this IContainer co // map to convert the non-unique keys into an unique ones: ContractName/Key -> { ContractType, count }[] container.Use(new ServiceKeyStore()); + var filterCollectionByMultiKey = Made.Of( + typeof(AttributedModel).SingleMethod(nameof(FilterCollectionByMultiKey), includeNonPublic: true), + parameters: Parameters.Of.Type(r => r.ServiceKey)); + // decorator to filter in a presence of multiple same keys // note: it is explicitly set to Transient to produce new results for new filtered collection, // otherwise it may be set to Singleton by container wide rules and always produce the results for the first resolved collection - container.Register(typeof(IEnumerable<>), Reuse.Transient, _filterCollectionByMultiKey, Setup.Decorator); + container.Register(typeof(IEnumerable<>), Reuse.Transient, filterCollectionByMultiKey, + Setup.DecoratorWith(condition: r => r.ServiceKey != null)); return container; } - private static readonly Made _filterCollectionByMultiKey = Made.Of( - typeof(AttributedModel).SingleMethod(nameof(FilterCollectionByMultiKey), includeNonPublic: true), - parameters: Parameters.Of.Type(request => request.ServiceKey)); - internal static IEnumerable FilterCollectionByMultiKey(IEnumerable> source, object serviceKey) => - serviceKey == null - ? source.Select(x => x.Value) // todo: @perf optimize - : source.Where(x => - { - if (x.Key is DefaultKey || x.Key is DefaultDynamicKey) - return false; - if (serviceKey.Equals(x.Key)) - return true; - var multiKey = x.Key as KV; - return multiKey != null && serviceKey.Equals(multiKey.Key); - }) - .Select(x => x.Value); + source.Match(x => + { + if (x.Key is DefaultKey || x.Key is DefaultDynamicKey) + return false; + if (serviceKey.Equals(x.Key)) + return true; + var multiKey = x.Key as KV; + return multiKey != null && serviceKey.Equals(multiKey.Key); + }, x => x.Value); #endregion diff --git a/src/DryIoc/Container.cs b/src/DryIoc/Container.cs index 6665fa262..7e41db2ad 100644 --- a/src/DryIoc/Container.cs +++ b/src/DryIoc/Container.cs @@ -1512,7 +1512,11 @@ Expression IContainer.GetDecoratorExpressionOrDefault(Request request) // Note: the condition for type arguments should be checked before generating the closed generic version var typeArgDecorators = container.GetDecoratorFactoriesOrDefault(typeof(object)); // todo: @perf add the rule for the object decorator to speedup the check if (!typeArgDecorators.IsNullOrEmpty()) - genericDecorators = genericDecorators.Append(typeArgDecorators.Match(request, (r, d) => d.CheckCondition(r))); + { + typeArgDecorators = typeArgDecorators.Match(request, (r, d) => d.CheckCondition(r)); + if (typeArgDecorators.Length > 0) + genericDecorators = genericDecorators.Append(typeArgDecorators); + } // Filter out already applied generic decorators // And combine with rest of decorators @@ -9179,7 +9183,7 @@ public Request Parent public int ReuseLifespan => Reuse?.Lifespan ?? 0; /// Known implementation, or otherwise actual service type. - public Type GetKnownImplementationOrServiceType() => ImplementationType ?? GetActualServiceType(); + public Type GetKnownImplementationOrServiceType() => _factoryImplType ?? Factory?.ImplementationType ?? _actualServiceType; /// Creates new request with provided info, and links current request as a parent. /// Allows to set some additional flags. Existing/parent request should be resolved to @@ -10168,7 +10172,11 @@ public virtual Setup Setup } /// Checks that condition is met for request or there is no condition setup. - public bool CheckCondition(Request request) => (Setup.Condition == null || Setup.Condition(request)); + public bool CheckCondition(Request request) + { + var condition = Setup.Condition; + return condition == null || condition(request); + } /// Shortcut for . public FactoryType FactoryType => Setup.FactoryType; diff --git a/test/DryIoc.IssuesTests/GHIssue417_Performance_degradation_with_dymanic_registrations_in_v4_compared_to_v2.cs b/test/DryIoc.IssuesTests/GHIssue417_Performance_degradation_with_dymanic_registrations_in_v4_compared_to_v2.cs index baa77c75d..5bff39f3b 100644 --- a/test/DryIoc.IssuesTests/GHIssue417_Performance_degradation_with_dymanic_registrations_in_v4_compared_to_v2.cs +++ b/test/DryIoc.IssuesTests/GHIssue417_Performance_degradation_with_dymanic_registrations_in_v4_compared_to_v2.cs @@ -18,6 +18,9 @@ public void SlowTest() var x = new Slow(); container.InjectPropertiesAndFields(x); + // var y = new Slow(); + // container.InjectPropertiesAndFields(y); + Assert.IsInstanceOf(x.ImportedServices[0].Value); }