Skip to content

Commit

Permalink
optimizing the decorator of Enumerable in MEF for the default key
Browse files Browse the repository at this point in the history
  • Loading branch information
dadhi committed Oct 17, 2021
1 parent cbb39f3 commit f4341b5
Show file tree
Hide file tree
Showing 4 changed files with 43 additions and 33 deletions.
5 changes: 4 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
{
"cSpell.words": [
"decoratee"
]
],
"files.watcherExclude": {
"**/target": true
}
}
54 changes: 25 additions & 29 deletions src/DryIoc.MefAttributedModel/AttributedModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -100,26 +100,24 @@ public static IContainer WithMefAttributedModel(this IContainer container) =>
/// <returns>The container with made registration.</returns>
public static IContainer WithImportsSatisfiedNotification(this IContainer container)
{
container.Register<object>(
made: _importsSatisfiedNotificationFactoryMethod,
setup: _importsSatisfiedNotificationDecoratorSetup);
var made = Made.Of(typeof(AttributedModel).SingleMethod(nameof(NotifyImportsSatisfied), includeNonPublic: true));

var decoratorSetup = Setup.DecoratorWith(
r => r.GetKnownImplementationOrServiceType().IsAssignableTo<IPartImportsSatisfiedNotification>(), // 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<object>(made: made, setup: decoratorSetup);

return container;
}

internal static TService NotifyImportsSatisfied<TService>(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<IPartImportsSatisfiedNotification>(),
order: int.MinValue, // Important, sets the decorator as a first one, so it will always being called
useDecorateeReuse: true);

#endregion

#region ExportFactory<T>, ExportFactory<T, TMetadata> and Lazy<T, TMetadata> support
Expand Down Expand Up @@ -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<T> FilterCollectionByMultiKey<T>(IEnumerable<KeyValuePair<object, T>> 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<object, int>;
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<object, int>;
return multiKey != null && serviceKey.Equals(multiKey.Key);
}, x => x.Value);

#endregion

Expand Down
14 changes: 11 additions & 3 deletions src/DryIoc/Container.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -9179,7 +9183,7 @@ public Request Parent
public int ReuseLifespan => Reuse?.Lifespan ?? 0;

/// <summary>Known implementation, or otherwise actual service type.</summary>
public Type GetKnownImplementationOrServiceType() => ImplementationType ?? GetActualServiceType();
public Type GetKnownImplementationOrServiceType() => _factoryImplType ?? Factory?.ImplementationType ?? _actualServiceType;

/// <summary>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
Expand Down Expand Up @@ -10168,7 +10172,11 @@ public virtual Setup Setup
}

/// <summary>Checks that condition is met for request or there is no condition setup.</summary>
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);
}

/// <summary>Shortcut for <see cref="DryIoc.Setup.FactoryType"/>.</summary>
public FactoryType FactoryType => Setup.FactoryType;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ public void SlowTest()
var x = new Slow();
container.InjectPropertiesAndFields(x);

// var y = new Slow();
// container.InjectPropertiesAndFields(y);

Assert.IsInstanceOf<MyService>(x.ImportedServices[0].Value);
}

Expand Down

0 comments on commit f4341b5

Please sign in to comment.