Skip to content

Commit

Permalink
Merge branch 'dev'
Browse files Browse the repository at this point in the history
  • Loading branch information
Peter Csajtai committed Jan 18, 2018
2 parents e5e80b0 + 2fb2460 commit 90f42d9
Show file tree
Hide file tree
Showing 11 changed files with 106 additions and 41 deletions.
2 changes: 1 addition & 1 deletion .version
Original file line number Diff line number Diff line change
@@ -1 +1 @@
2.5.6
2.5.7
14 changes: 4 additions & 10 deletions coverage.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,12 @@
exit 0
}

nuget install OpenCover -Version 4.6.519 -OutputDirectory .\tools
nuget install ReportGenerator -Version 2.5.2 -OutputDirectory .\tools
choco install opencover.portable
choco install codecov

$openCoverPath = Join-Path $PSScriptRoot "tools\OpenCover.4.6.519\tools\OpenCover.Console.exe"
$reportGeneratorPath = Join-Path $PSScriptRoot "tools\ReportGenerator.2.5.2\tools\ReportGenerator.exe"
$testPath = Join-Path $PSScriptRoot "src\stashbox.tests\stashbox.tests.csproj"
$coverageReportDir = Join-Path $PSScriptRoot "coverageresults"

$env:Path += ";c:\Python34;C:\Python34\Scripts"

$arguments = "-returntargetcode", "-register:user", "`"-filter:+[*]Stashbox.* -[Stashbox.Tests]* -[Stashbox]*.Utils* -[Stashbox]*.Expressions.Compile*`"", "-target:dotnet.exe", "`"-targetargs:test $testPath -f net45 -c Release`"", "-output:coverage.xml", "-skipautoprops", "-hideskipped:All"
. $openCoverPath $arguments
. pip install codecov
. codecov -f coverage.xml -X gcov
. $reportGeneratorPath -verbosity:Info -reports:coverage.xml -targetdir:$coverageReportDir "-assemblyfilters:-Stashbox.Tests*"
. OpenCover.Console.exe $arguments
. codecov -f coverage.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;

namespace Stashbox.Tests.IssueTests
{
[TestClass]
public class ResolverFactoryIssue
{
[TestMethod]
public void Resolver_factory_invoke_doesnt_pass_different_parameters_given_when_theyre_the_same_type()
{
var factory = new StashboxContainer()
.RegisterType<IFoo, Foobar>()
.ResolveFactory(typeof(IFoo), parameterTypes: new[] { typeof(string), typeof(string) });

Assert.AreEqual("foobar", ((IFoo)factory.DynamicInvoke("foo", "bar")).Result);
}

[TestMethod]
public void Resolver_factory_invoke_doesnt_pass_different_parameters_given_when_theyre_the_same_type_func()
{
var factory = new StashboxContainer()
.RegisterType<IFoo, Foobar>()
.Resolve<Func<string, string, IFoo>>();

Assert.AreEqual("foobar", factory("foo", "bar").Result);
}

interface IFoo
{
string Result { get; set; }
}

class Foobar : IFoo
{
public Foobar(string x, string y)
{
this.Result = x + y;
}

public string Result { get; set; }
}
}
}
1 change: 0 additions & 1 deletion src/stashbox/BuildUp/DefaultObjectBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
using Stashbox.Infrastructure;
using Stashbox.Infrastructure.Registration;
using Stashbox.Resolution;
using Stashbox.Utils;
using System;
using System.Linq.Expressions;

Expand Down
4 changes: 2 additions & 2 deletions src/stashbox/BuildUp/Resolution/FuncResolver.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ public override Expression GetExpression(IContainerContext containerContext, Typ
var parameters = this.PrepareExtraParameters(wrappedType, resolutionContext, args);
var expression = containerContext.ResolutionStrategy.BuildResolutionExpression(containerContext, resolutionContext, funcArgumentInfo, null);

return expression != null ? expression.AsLambda(parameters) : null;
return expression?.AsLambda(parameters);
}

public override Expression[] GetExpressions(IContainerContext containerContext, TypeInformation typeInfo, ResolutionContext resolutionContext)
Expand Down Expand Up @@ -72,9 +72,9 @@ private ParameterExpression[] PrepareExtraParameters(Type wrappedType, Resolutio
var argName = wrappedType.Name + argType.Name + i;
var parameter = argType.AsParameter(argName);
parameters[i] = parameter;
resolutionContext.AddParameterExpressions(parameter);
}

resolutionContext.AddParameterExpressions(wrappedType, parameters);
return parameters;
}
}
Expand Down
12 changes: 9 additions & 3 deletions src/stashbox/BuildUp/Resolution/LazyResolver.cs
Original file line number Diff line number Diff line change
Expand Up @@ -75,12 +75,18 @@ public override Expression[] GetExpressions(IContainerContext containerContext,
private static Expression CreateLazyExpressionCall(IContainerContext containerContext, IServiceRegistration serviceRegistration, Type type, ConstructorInfo constructor, ResolutionContext resolutionContext)
{
var arguments = resolutionContext.ParameterExpressions != null
? new Expression[resolutionContext.ParameterExpressions.Length]
? new Expression[resolutionContext.ParameterExpressions.Sum(x => x.Length)]
: new Expression[0];

if (resolutionContext.ParameterExpressions != null)
{
var index = 0;
for (var i = 0; i < resolutionContext.ParameterExpressions.Length; i++)
arguments[i] = resolutionContext.ParameterExpressions[i].ConvertTo(typeof(object));
for (var j = 0; j < resolutionContext.ParameterExpressions[i].Length; j++)
arguments[index++] = resolutionContext.ParameterExpressions[i][j].ConvertTo(typeof(object));
}



var callExpression = DelegateCacheMethod.InvokeMethod(
containerContext.AsConstant(),
Expand All @@ -100,7 +106,7 @@ public override bool CanUseForResolution(IContainerContext containerContext, Typ
private static object CreateLazyDelegate(IContainerContext containerContext, IServiceRegistration serviceRegistration, ResolutionContext resolutionContext, Type type, object[] arguments)
{
var expr = serviceRegistration.GetExpression(containerContext, resolutionContext, type);
return expr.AsLambda(resolutionContext.ParameterExpressions)
return expr.AsLambda(resolutionContext.ParameterExpressions.SelectMany(x => x))
.CompileDynamicDelegate(resolutionContext)(resolutionContext.ResolutionScope).DynamicInvoke(arguments);
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
using System;
using Stashbox.Infrastructure;
using Stashbox.Infrastructure;
using System;

namespace Stashbox
{
Expand Down Expand Up @@ -37,8 +37,8 @@ public static IStashboxContainer WireUp(this IDependencyRegistrator registrator,
/// <typeparam name="TTo">Type that will be returned.</typeparam>
/// <param name="registrator">The dependency registrator.</param>
/// <param name="name">The name of the registration.</param>
/// <returns>The <see cref="IDependencyRegistrator"/> which on this method was called.</returns>
public static IDependencyRegistrator RegisterSingleton<TFrom, TTo>(this IDependencyRegistrator registrator, object name = null)
/// <returns>The <see cref="IStashboxContainer"/> which on this method was called.</returns>
public static IStashboxContainer RegisterSingleton<TFrom, TTo>(this IDependencyRegistrator registrator, object name = null)
where TFrom : class
where TTo : class, TFrom =>
registrator.RegisterType<TFrom, TTo>(context => context.WithName(name).WithSingletonLifetime());
Expand All @@ -49,8 +49,8 @@ public static IDependencyRegistrator RegisterSingleton<TFrom, TTo>(this IDepende
/// <typeparam name="TTo">Type that will be returned.</typeparam>
/// <param name="registrator">The dependency registrator.</param>
/// <param name="name">The name of the registration.</param>
/// <returns>The <see cref="IDependencyRegistrator"/> which on this method was called.</returns>
public static IDependencyRegistrator RegisterSingleton<TTo>(this IDependencyRegistrator registrator, object name = null)
/// <returns>The <see cref="IStashboxContainer"/> which on this method was called.</returns>
public static IStashboxContainer RegisterSingleton<TTo>(this IDependencyRegistrator registrator, object name = null)
where TTo : class =>
registrator.RegisterType<TTo>(context => context.WithName(name).WithSingletonLifetime());

Expand All @@ -61,8 +61,8 @@ public static IDependencyRegistrator RegisterSingleton<TTo>(this IDependencyRegi
/// <param name="typeFrom">Type that will be requested.</param>
/// <param name="typeTo">Type that will be returned.</param>
/// <param name="name">The name of the registration.</param>
/// <returns>The <see cref="IDependencyRegistrator"/> which on this method was called.</returns>
public static IDependencyRegistrator RegisterSingleton(this IDependencyRegistrator registrator, Type typeFrom, Type typeTo, object name = null) =>
/// <returns>The <see cref="IStashboxContainer"/> which on this method was called.</returns>
public static IStashboxContainer RegisterSingleton(this IDependencyRegistrator registrator, Type typeFrom, Type typeTo, object name = null) =>
registrator.RegisterType(typeFrom, typeTo, context => context.WithName(name).WithSingletonLifetime());

/// <summary>
Expand All @@ -72,8 +72,8 @@ public static IDependencyRegistrator RegisterSingleton(this IDependencyRegistrat
/// <typeparam name="TTo">Type that will be returned.</typeparam>
/// <param name="registrator">The dependency registrator.</param>
/// <param name="name">The name of the registration.</param>
/// <returns>The <see cref="IDependencyRegistrator"/> which on this method was called.</returns>
public static IDependencyRegistrator RegisterScoped<TFrom, TTo>(this IDependencyRegistrator registrator, object name = null)
/// <returns>The <see cref="IStashboxContainer"/> which on this method was called.</returns>
public static IStashboxContainer RegisterScoped<TFrom, TTo>(this IDependencyRegistrator registrator, object name = null)
where TFrom : class
where TTo : class, TFrom =>
registrator.RegisterType<TFrom, TTo>(context => context.WithName(name).WithScopedLifetime());
Expand All @@ -85,8 +85,8 @@ public static IDependencyRegistrator RegisterScoped<TFrom, TTo>(this IDependency
/// <param name="typeTo">Type that will be returned.</param>
/// <param name="registrator">The dependency registrator.</param>
/// <param name="name">The name of the registration.</param>
/// <returns>The <see cref="IDependencyRegistrator"/> which on this method was called.</returns>
public static IDependencyRegistrator RegisterScoped(this IDependencyRegistrator registrator, Type typeFrom, Type typeTo, object name = null) =>
/// <returns>The <see cref="IStashboxContainer"/> which on this method was called.</returns>
public static IStashboxContainer RegisterScoped(this IDependencyRegistrator registrator, Type typeFrom, Type typeTo, object name = null) =>
registrator.RegisterType(typeFrom, typeTo, context => context.WithName(name).WithScopedLifetime());

/// <summary>
Expand All @@ -95,8 +95,8 @@ public static IDependencyRegistrator RegisterScoped(this IDependencyRegistrator
/// <typeparam name="TTo">Type that will be returned.</typeparam>
/// <param name="registrator">The dependency registrator.</param>
/// <param name="name">The name of the registration.</param>
/// <returns>The <see cref="IDependencyRegistrator"/> which on this method was called.</returns>
public static IDependencyRegistrator RegisterScoped<TTo>(this IDependencyRegistrator registrator, object name = null)
/// <returns>The <see cref="IStashboxContainer"/> which on this method was called.</returns>
public static IStashboxContainer RegisterScoped<TTo>(this IDependencyRegistrator registrator, object name = null)
where TTo : class =>
registrator.RegisterType<TTo>(context => context.WithName(name).WithScopedLifetime());
}
Expand Down
18 changes: 12 additions & 6 deletions src/stashbox/Resolution/ResolutionContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ public static ResolutionContext New(IResolutionScope scope, bool nullResultAllow
private AvlTree<Expression> expressionOverrides;
private AvlTree<Type> currentlyDecoratingTypes;
private AvlTreeKeyValue<int, bool> circularDependencyBarrier;

private readonly ArrayStoreKeyed<object, ParameterExpression> knownVariables;

internal IResolutionScope ResolutionScope { get; }
Expand All @@ -42,19 +42,19 @@ public static ResolutionContext New(IResolutionScope scope, bool nullResultAllow
internal IContainerContext ChildContext { get; }
internal ISet<object> ScopeNames { get; }

internal ArrayStore<ParameterExpression> ParameterExpressions { get; private set; }
internal ArrayStore<ArrayStoreKeyed<bool, ParameterExpression>> ParameterExpressions { get; private set; }

internal ArrayStore<Expression> SingleInstructions { get; private set; }

internal ArrayStoreKeyed<object, ParameterExpression> DefinedVariables { get; private set; }

private ResolutionContext(IResolutionScope scope, bool nullResultAllowed)
: this(scope, AvlTreeKeyValue<int, bool>.Empty, AvlTree<Expression>.Empty, AvlTree<Type>.Empty, ArrayStore<ParameterExpression>.Empty, scope.GetActiveScopeNames(),
: this(scope, AvlTreeKeyValue<int, bool>.Empty, AvlTree<Expression>.Empty, AvlTree<Type>.Empty, ArrayStore<ArrayStoreKeyed<bool, ParameterExpression>>.Empty, scope.GetActiveScopeNames(),
null, nullResultAllowed, Constants.ResolutionScopeParameter, ArrayStoreKeyed<object, ParameterExpression>.Empty)
{ }

private ResolutionContext(IResolutionScope scope, AvlTreeKeyValue<int, bool> circularDependencyBarrier, AvlTree<Expression> expressionOverrides,
AvlTree<Type> currentlyDecoratingTypes, ArrayStore<ParameterExpression> parameterExpressions, ISet<object> scopeNames,
AvlTree<Type> currentlyDecoratingTypes, ArrayStore<ArrayStoreKeyed<bool, ParameterExpression>> parameterExpressions, ISet<object> scopeNames,
IContainerContext childContext, bool nullResultAllowed, ParameterExpression currentScope, ArrayStoreKeyed<object, ParameterExpression> knownVariables)
{
this.DefinedVariables = ArrayStoreKeyed<object, ParameterExpression>.Empty;
Expand Down Expand Up @@ -117,8 +117,14 @@ internal Expression GetExpressionOverrideOrDefault(Type type) =>
internal void SetExpressionOverride(Type type, Expression expression) =>
this.expressionOverrides = this.expressionOverrides.AddOrUpdate(type.GetHashCode(), expression, (oldValue, newValue) => newValue);

internal void AddParameterExpressions(params ParameterExpression[] parameterExpressions) =>
this.ParameterExpressions = this.ParameterExpressions.AddRange(parameterExpressions);
internal void AddParameterExpressions(Type scopeType, ParameterExpression[] parameterExpressions)
{
var length = parameterExpressions.Length;
var newItems = new KeyValue<bool, ParameterExpression>[length];
for (var i = 0; i < length; i++)
newItems[i] = new KeyValue<bool, ParameterExpression>(false, parameterExpressions[i]);
this.ParameterExpressions = this.ParameterExpressions.Add(new ArrayStoreKeyed<bool, ParameterExpression>(newItems));
}

internal void SetCircularDependencyBarrier(int key, bool value) =>
Swap.SwapValue(ref this.circularDependencyBarrier, barrier => barrier.AddOrUpdate(key, value, (old, @new) => @new));
Expand Down
16 changes: 14 additions & 2 deletions src/stashbox/Resolution/ResolutionStrategy.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,20 @@ public Expression BuildResolutionExpression(IContainerContext containerContext,
if (typeInformation.Type == Constants.ResolverType)
return resolutionContext.CurrentScopeParameter.ConvertTo(Constants.ResolverType);

if (resolutionContext.ParameterExpressions.Length > 0 && resolutionContext.ParameterExpressions.Any(p => p.Type == typeInformation.Type || p.Type.Implements(typeInformation.Type)))
return resolutionContext.ParameterExpressions.Last(p => p.Type == typeInformation.Type || p.Type.Implements(typeInformation.Type));
if (resolutionContext.ParameterExpressions.Length > 0)
{
var length = resolutionContext.ParameterExpressions.Length;
for (var i = length; i-- > 0;)
{
var parameters = resolutionContext.ParameterExpressions[i].WhereOrDefault(p => p.Value.Type == typeInformation.Type ||
p.Value.Type.Implements(typeInformation.Type));

if (parameters == null) continue;
var selected = parameters.Repository.FirstOrDefault(parameter => !parameter.Key) ?? parameters.Repository.Last();
selected.Key = true;
return selected.Value;
}
}

var matchingParam = injectionParameters?.FirstOrDefault(param => param.Name == typeInformation.ParameterName);
if (matchingParam != null)
Expand Down
4 changes: 2 additions & 2 deletions src/stashbox/ResolutionScope.cs
Original file line number Diff line number Diff line change
Expand Up @@ -291,7 +291,7 @@ private object Activate(ResolutionContext resolutionContext, Type type, int hash
private Delegate ActivateFactoryDelegate(Type type, Type[] parameterTypes, IResolutionScope resolutionScope, object name, bool nullResultAllowed, int hash)
{
var resolutionContext = ResolutionContext.New(resolutionScope, nullResultAllowed);
resolutionContext.AddParameterExpressions(parameterTypes.Select(p => p.AsParameter()).ToArray());
resolutionContext.AddParameterExpressions(type, parameterTypes.Select(p => p.AsParameter()).ToArray());

var typeInfo = new TypeInformation { Type = type, DependencyName = name };
var registration = this.containerContext.RegistrationRepository.GetRegistrationOrDefault(typeInfo, resolutionContext);
Expand All @@ -306,7 +306,7 @@ private Delegate ActivateFactoryDelegate(Type type, Type[] parameterTypes, IReso
else
throw new ResolutionFailedException(type);

var expression = initExpression.AsLambda(resolutionContext.ParameterExpressions);
var expression = initExpression.AsLambda(resolutionContext.ParameterExpressions.SelectMany(x => x));

var factory = expression.CompileDynamicDelegate(resolutionContext);
Swap.SwapValue(ref this.factoryDelegates[hash & this.indexBound], c => c.AddOrUpdate(hash, name ?? type, factory));
Expand Down
4 changes: 4 additions & 0 deletions src/stashbox/stashbox.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@
<GeneratePackageOnBuild>false</GeneratePackageOnBuild>
<DebugType>portable</DebugType>
<PackageReleaseNotes>
v2.5.7
- fixed: #37 Resolver factory invoke doesn't pass different parameters given when they're the same type
v2.5.6
- fixed: #36 Nullreference on fetching custom attributes under netcoreapp1.1 target
v2.5.5
- fixed: #35 Mixture of named and non named registrations result in the wrong type resolved
- fixed: #34 Resolution from parent container not working well
Expand Down

0 comments on commit 90f42d9

Please sign in to comment.