Skip to content

Commit

Permalink
Improved performance of Resolve()
Browse files Browse the repository at this point in the history
  • Loading branch information
remogloor committed Apr 25, 2014
1 parent d118f7c commit 894be4b
Show file tree
Hide file tree
Showing 2 changed files with 69 additions and 46 deletions.
79 changes: 51 additions & 28 deletions src/Ninject/ReadonlyKernel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -93,48 +93,40 @@ public void Inject(object instance, params IParameter[] parameters)
public bool CanResolve(IRequest request)
{
Ensure.ArgumentNotNull(request, "request");
return this.GetBindings(request.Service).Any(this.SatifiesRequest(request));
return this.GetBindings(request.Service).Any(b => this.SatifiesRequest(request, b));
}

/// <inheritdoc />
public bool CanResolve(IRequest request, bool ignoreImplicitBindings)
{
Ensure.ArgumentNotNull(request, "request");
return this.GetBindings(request.Service)
.Any(binding => (!ignoreImplicitBindings || !binding.IsImplicit) && this.SatifiesRequest(request)(binding));
.Any(binding => (!ignoreImplicitBindings || !binding.IsImplicit) && this.SatifiesRequest(request, binding));
}

/// <inheritdoc />
public IEnumerable<object> Resolve(IRequest request)
{
Ensure.ArgumentNotNull(request, "request");

var resolveBindings = Enumerable.Empty<IBinding>();
return Resolve(request, true);
}

if (this.CanResolve(request) || this.HandleMissingBinding(request))
{
resolveBindings = this.GetBindings(request.Service)
.Where(this.SatifiesRequest(request));
}
private IEnumerable<object> Resolve(IRequest request, bool requestMissingBindings)
{
var resolveBindings = this.GetBindings(request.Service).Where(b => this.SatifiesRequest(request, b));
var resolveBindingsIterator = resolveBindings.GetEnumerator();

if (!resolveBindings.Any())
if (!resolveBindingsIterator.MoveNext())
{
if (request.IsOptional)
{
return Enumerable.Empty<object>();
}

throw new ActivationException(ExceptionFormatter.CouldNotResolveBinding(request));
return this.ResolveWithMissingBindings(request, requestMissingBindings);
}

if (request.IsUnique)
{
resolveBindings = resolveBindings.OrderByDescending(b => b, this.bindingPrecedenceComparer).ToList();
var model = resolveBindings.First(); // the type (conditonal, implicit, etc) of binding we'll return
resolveBindings =
resolveBindings.TakeWhile(binding => this.bindingPrecedenceComparer.Compare(binding, model) == 0);

if (resolveBindings.Count() > 1)
var first = resolveBindingsIterator.Current;
if (resolveBindingsIterator.MoveNext() &&
this.bindingPrecedenceComparer.Compare(first, resolveBindingsIterator.Current) == 0)
{
if (request.IsOptional && !request.ForceUnique)
{
Expand All @@ -147,15 +139,43 @@ from binding in resolveBindings
select binding.Format(context);
throw new ActivationException(ExceptionFormatter.CouldNotUniquelyResolveBinding(request, formattedBindings.ToArray()));
}

return new object[] { this.CreateContext(request, first).Resolve() };
}
else
{
return this.ResolveMultiple(request);
}
}

private IEnumerable<object> ResolveMultiple(IRequest request)
{
var selectedBindings = this.GetBindings(request.Service).Where(b => this.SatifiesRequest(request, b));
var skipImplicit = false;

foreach (var binding in selectedBindings.TakeWhile(binding => !binding.IsImplicit || !skipImplicit))
{
skipImplicit = !binding.IsImplicit;
yield return this.CreateContext(request, binding).Resolve();
}
}

private IEnumerable<object> ResolveWithMissingBindings(IRequest request, bool handleMissingBindings)
{
if (handleMissingBindings)
{
if (this.HandleMissingBinding(request))
{
return this.Resolve(request, false);
}
}

if (resolveBindings.Any(binding => !binding.IsImplicit))
if (request.IsOptional)
{
resolveBindings = resolveBindings.Where(binding => !binding.IsImplicit);
return Enumerable.Empty<object>();
}

return resolveBindings
.Select(binding => this.CreateContext(request, binding).Resolve());
throw new ActivationException(ExceptionFormatter.CouldNotResolveBinding(request));
}

/// <inheritdoc />
Expand Down Expand Up @@ -211,7 +231,9 @@ public IEnumerable<IBinding> GetBindings(Type service)
return result;
}

result = bindingResolvers.SelectMany(resolver => resolver.Resolve(this.bindings, service)).ToList();
result = bindingResolvers.SelectMany(resolver => resolver.Resolve(this.bindings, service))
.OrderByDescending(b => b, bindingPrecedenceComparer)
.ToList();
if (result.Count > 0)
{
newBindingCache[service] = result;
Expand All @@ -228,10 +250,11 @@ public IEnumerable<IBinding> GetBindings(Type service)
/// Returns a predicate that can determine if a given IBinding matches the request.
/// </summary>
/// <param name="request">The request/</param>
/// <param name="binding">The binding</param>
/// <returns>A predicate that can determine if a given IBinding matches the request.</returns>
protected virtual Func<IBinding, bool> SatifiesRequest(IRequest request)
protected virtual bool SatifiesRequest(IRequest request, IBinding binding)
{
return binding => binding.Matches(request) && request.Matches(binding);
return binding.Matches(request) && request.Matches(binding);
}

/// <summary>
Expand Down
36 changes: 18 additions & 18 deletions src/Ninject/Syntax/ResolutionExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ public static T Get<T>(this IResolutionRoot root, Func<IBindingMetadata, bool> c
/// <returns>An instance of the service, or <see langword="null"/> if no implementation was available.</returns>
public static T TryGet<T>(this IResolutionRoot root, params IParameter[] parameters)
{
return TryGet(GetResolutionIterator(root, typeof(T), null, parameters, true, true).Cast<T>());
return TryGet(() => GetResolutionIterator(root, typeof(T), null, parameters, true, true).Cast<T>());
}

/// <summary>
Expand All @@ -85,7 +85,7 @@ public static T TryGet<T>(this IResolutionRoot root, params IParameter[] paramet
/// <returns>An instance of the service, or <see langword="null"/> if no implementation was available.</returns>
public static T TryGet<T>(this IResolutionRoot root, string name, params IParameter[] parameters)
{
return TryGet(GetResolutionIterator(root, typeof(T), b => b.Name == name, parameters, true, true).Cast<T>());
return TryGet(()=> GetResolutionIterator(root, typeof(T), b => b.Name == name, parameters, true, true).Cast<T>());
}

/// <summary>
Expand All @@ -98,7 +98,7 @@ public static T TryGet<T>(this IResolutionRoot root, string name, params IParame
/// <returns>An instance of the service, or <see langword="null"/> if no implementation was available.</returns>
public static T TryGet<T>(this IResolutionRoot root, Func<IBindingMetadata, bool> constraint, params IParameter[] parameters)
{
return TryGet(GetResolutionIterator(root, typeof(T), constraint, parameters, true, true).Cast<T>());
return TryGet(() => GetResolutionIterator(root, typeof(T), constraint, parameters, true, true).Cast<T>());
}

/// <summary>
Expand Down Expand Up @@ -224,7 +224,7 @@ public static object Get(this IResolutionRoot root, Type service, Func<IBindingM
/// <returns>An instance of the service, or <see langword="null"/> if no implementation was available.</returns>
public static object TryGet(this IResolutionRoot root, Type service, params IParameter[] parameters)
{
return TryGet(GetResolutionIterator(root, service, null, parameters, true, true));
return TryGet(() => GetResolutionIterator(root, service, null, parameters, true, true));
}

/// <summary>
Expand All @@ -237,7 +237,7 @@ public static object TryGet(this IResolutionRoot root, Type service, params IPar
/// <returns>An instance of the service, or <see langword="null"/> if no implementation was available.</returns>
public static object TryGet(this IResolutionRoot root, Type service, string name, params IParameter[] parameters)
{
return TryGet(GetResolutionIterator(root, service, b => b.Name == name, parameters, true, false));
return TryGet(() => GetResolutionIterator(root, service, b => b.Name == name, parameters, true, false));
}

/// <summary>
Expand All @@ -250,7 +250,7 @@ public static object TryGet(this IResolutionRoot root, Type service, string name
/// <returns>An instance of the service, or <see langword="null"/> if no implementation was available.</returns>
public static object TryGet(this IResolutionRoot root, Type service, Func<IBindingMetadata, bool> constraint, params IParameter[] parameters)
{
return TryGet(GetResolutionIterator(root, service, constraint, parameters, true, false));
return TryGet(() => GetResolutionIterator(root, service, constraint, parameters, true, false));
}

/// <summary>
Expand Down Expand Up @@ -396,18 +396,18 @@ private static IEnumerable<object> GetResolutionIterator(IResolutionRoot root, T
IRequest request = root.CreateRequest(service, constraint, parameters, isOptional, isUnique);
request.ForceUnique = forceUnique;
return root.Resolve(request);
}

private static T TryGet<T>(IEnumerable<T> iterator)
{
try
{
return iterator.SingleOrDefault();
}
catch (ActivationException)
{
return default(T);
}
}

private static T TryGet<T>(Func<IEnumerable<T>> getResolutionCallback)
{
try
{
return getResolutionCallback().SingleOrDefault();
}
catch (ActivationException)
{
return default(T);
}
}

private static T DoTryGetAndThrowOnInvalidBinding<T>(IResolutionRoot root, Func<IBindingMetadata, bool> constraint, IEnumerable<IParameter> parameters)
Expand Down

0 comments on commit 894be4b

Please sign in to comment.