Skip to content

Commit

Permalink
Improve performance of expressions build
Browse files Browse the repository at this point in the history
  • Loading branch information
NikolayPianikov authored and NikolayPianikov committed May 14, 2021
1 parent 3d0e35c commit b302da6
Show file tree
Hide file tree
Showing 2 changed files with 35 additions and 27 deletions.
36 changes: 23 additions & 13 deletions IoC/Core/BuildContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ internal sealed class BuildContext : IBuildContext
[NotNull] private readonly IObserver<ContainerEvent> _eventObserver;
private readonly IList<ParameterExpression> _parameters = new List<ParameterExpression>();
[NotNull] private readonly IDictionary<Type, Type> _typesMap;
private IDictionary<Key, Expression> _cache = new Dictionary<Key, Expression>();

internal BuildContext(
[CanBeNull] BuildContext parent,
Expand Down Expand Up @@ -60,20 +61,25 @@ internal BuildContext(

public ParameterExpression ContainerParameter { get; private set; }

public IBuildContext CreateChild(Key key, IContainer container) =>
CreateInternal(key, container ?? throw new ArgumentNullException(nameof(container)));
public IBuildContext CreateChild(Key key, IContainer container)
{
return CreateInternal(key, container ?? throw new ArgumentNullException(nameof(container)));
}

public Expression CreateExpression(Expression defaultExpression = null)
{
if (Key.Type == typeof(IBuildContext))
{
return Expression.Constant(Parent);
}

var selectedContainer = Container;
if (selectedContainer.Parent != null)
{
var parent = Parent;
while (parent != null)
{
if (
Key.Equals(parent.Key)
&& Equals(parent.Container, selectedContainer))
if (Key.Equals(parent.Key) && Equals(parent.Container, selectedContainer))
{
selectedContainer = selectedContainer.Parent;
break;
Expand All @@ -83,14 +89,9 @@ public Expression CreateExpression(Expression defaultExpression = null)
}
}

if (Key.Type == typeof(IBuildContext))
{
return Expression.Constant(Parent);
}

if (!selectedContainer.TryGetDependency(Key, out var dependency, out var lifetime))
{
if (Container == selectedContainer || !Container.TryGetDependency(Key, out dependency, out lifetime))
if (Equals(Container, selectedContainer) || !Container.TryGetDependency(Key, out dependency, out lifetime))
{
if (defaultExpression != null)
{
Expand All @@ -115,8 +116,14 @@ public Expression CreateExpression(Expression defaultExpression = null)
Container.Resolve<IFoundCyclicDependency>().Resolve(this);
}

if (dependency.TryBuildExpression(this, lifetime, out var expression, out var error))
if (_cache.TryGetValue(Key, out var expression))
{
return expression;
}

if (dependency.TryBuildExpression(this, lifetime, out expression, out var error))
{
_cache[Key] = expression;
return expression;
}

Expand Down Expand Up @@ -188,7 +195,10 @@ private IBuildContext CreateInternal(Key key, IContainer container)
ArgsParameter,
ContainerParameter,
_eventObserver,
Depth + 1);
Depth + 1)
{
_cache = _cache
};
}

public override string ToString()
Expand Down
26 changes: 12 additions & 14 deletions IoC/Core/DependencyInjectionExpressionVisitor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -286,29 +286,27 @@ private Expression CreateNewContextExpression() =>
private object GetTag([NotNull] Expression tagExpression)
{
if (tagExpression == null) throw new ArgumentNullException(nameof(tagExpression));
object tag;
switch (tagExpression)
{
case ConstantExpression constant:
tag = constant.Value;
break;
return constant.Value;

default:
// ReSharper disable once ConstantNullCoalescingCondition
var expression = Visit(tagExpression) ?? throw new BuildExpressionException($"Invalid tag expression {tagExpression}.", new InvalidOperationException());
if (_buildContext.TryCompile(Expression.Lambda(expression, true), out var tagFunc, out var error))
{
tag = ((Func<object>)tagFunc)();
}
else
case UnaryExpression unary:
if (unary.NodeType == ExpressionType.Convert)
{
throw error;
return GetTag(unary.Operand);
}

break;
}

return tag;
// ReSharper disable once ConstantNullCoalescingCondition
var expression = Visit(tagExpression) ?? throw new BuildExpressionException($"Invalid tag expression {tagExpression}.", new InvalidOperationException());
if (_buildContext.TryCompile(Expression.Lambda(expression.Convert(typeof(object)), true), out var tagFunc, out var error))
{
return ((Func<object>)tagFunc)();
}

throw error;
}

private IEnumerable<Expression> InjectAll(IEnumerable<Expression> expressions) =>
Expand Down

0 comments on commit b302da6

Please sign in to comment.