Ensure that FactoryCreators also build up the result

This commit is contained in:
Antony Male 2014-03-23 18:13:01 +00:00
parent 316d9a5e49
commit fc156247b0
4 changed files with 58 additions and 27 deletions

View File

@ -17,20 +17,46 @@ namespace StyletIoC
internal abstract class CreatorBase : ICreator
{
public virtual Type Type { get; protected set; }
protected StyletIoCContainer container;
public abstract Expression GetInstanceExpression();
public CreatorBase(StyletIoCContainer container)
{
this.container = container;
}
// Common utility method
protected Expression CompleteExpressionFromCreator(Expression creator)
{
var instanceVar = Expression.Variable(this.Type, "instance");
var assignment = Expression.Assign(instanceVar, creator);
var buildUpExpression = this.container.GetBuilderUpper(this.Type).GetExpression(instanceVar);
// We always start with:
// var instance = new Class(.....)
// instance.Property1 = new ....
// instance.Property2 = new ....
var blockItems = new List<Expression>() { assignment, buildUpExpression };
// If it implements IInjectionAware, follow that up with:
// instance.ParametersInjected
if (typeof(IInjectionAware).IsAssignableFrom(this.Type))
blockItems.Add(Expression.Call(instanceVar, typeof(IInjectionAware).GetMethod("ParametersInjected")));
// Final appearance of instanceVar, as this sets the return value of the block
blockItems.Add(instanceVar);
var completeExpression = Expression.Block(new[] { instanceVar }, blockItems);
return completeExpression;
}
}
internal class TypeCreator : CreatorBase
{
private StyletIoCContainer container;
public string AttributeKey { get; private set; }
private Expression creationExpression;
public TypeCreator(Type type, StyletIoCContainer container)
public TypeCreator(Type type, StyletIoCContainer container) : base(container)
{
this.Type = type;
this.container = container;
// Use the key from InjectAttribute (if present), and let someone else override it if they want
var attribute = (InjectAttribute)type.GetCustomAttributes(typeof(InjectAttribute), false).FirstOrDefault();
@ -101,24 +127,9 @@ namespace StyletIoC
return Expression.Convert(Expression.Constant(x.DefaultValue), x.ParameterType);
});
var instanceVar = Expression.Variable(this.Type, "instance");
var creator = Expression.New(ctor, ctorParams);
var assignment = Expression.Assign(instanceVar, creator);
var buildUpExpression = this.container.GetBuilderUpper(this.Type).GetExpression(instanceVar);
// We always start with:
// var instance = new Class(.....)
// instance.Property1 = new ....
// instance.Property2 = new ....
var blockItems = new List<Expression>() { assignment, buildUpExpression };
// If it implements IInjectionAware, follow that up with:
// instance.ParametersInjected
if (typeof(IInjectionAware).IsAssignableFrom(this.Type))
blockItems.Add(Expression.Call(instanceVar, typeof(IInjectionAware).GetMethod("ParametersInjected")));
// Final appearance of instanceVar, as this sets the return value of the block
blockItems.Add(instanceVar);
var completeExpression = Expression.Block(new[] { instanceVar }, blockItems);
var completeExpression = this.CompleteExpressionFromCreator(creator);
this.creationExpression = completeExpression;
return completeExpression;
@ -128,20 +139,27 @@ namespace StyletIoC
internal class FactoryCreator<T> : CreatorBase
{
private Func<StyletIoCContainer, T> factory;
private StyletIoCContainer container;
private Expression instanceExpression;
public override Type Type { get { return typeof(T); } }
public FactoryCreator(Func<StyletIoCContainer, T> factory, StyletIoCContainer container)
public FactoryCreator(Func<StyletIoCContainer, T> factory, StyletIoCContainer container) : base(container)
{
this.factory = factory;
this.container = container;
}
public override Expression GetInstanceExpression()
{
if (this.instanceExpression != null)
return this.instanceExpression;
var expr = (Expression<Func<T>>)(() => this.factory(this.container));
return Expression.Invoke(expr, null);
var invoked = Expression.Invoke(expr, null);
var completeExpression = this.CompleteExpressionFromCreator(invoked);
this.instanceExpression = completeExpression;
return completeExpression;
}
}
}

View File

@ -9,7 +9,7 @@ using System.Threading.Tasks;
namespace StyletUnitTests
{
[TestFixture]
public class StyletIoCParameterInjectionTests
public class StyletIoCPropertyInjectionTests
{
class C1 { }
interface I2 { }
@ -175,5 +175,18 @@ namespace StyletUnitTests
Assert.IsInstanceOf<C1>(subject.C1);
Assert.IsTrue(subject.ParametersInjectedCalledCorrectly);
}
[Test]
public void FactoryCreatorBuildsUp()
{
var builder = new StyletIoCBuilder();
builder.Bind<C1>().ToSelf();
builder.Bind<Subject1>().ToFactory(c => new Subject1());
var ioc = builder.BuildContainer();
var subject = ioc.Get<Subject1>();
Assert.IsInstanceOf<C1>(subject.C1);
}
}
}

View File

@ -61,13 +61,13 @@
<Compile Include="PropertyChangedExtensionsTests.cs" />
<Compile Include="StyletIoC\StyletIoCAutobindingTests.cs" />
<Compile Include="StyletIoC\StyletIoCBindingChecksTests.cs" />
<Compile Include="StyletIoC\StyletIoCParameterInjectionTests.cs" />
<Compile Include="StyletIoC\StyletIoCPropertyInjectionTests.cs" />
<Compile Include="StyletIoC\StyletIoCConstructorInjectionTests.cs" />
<Compile Include="StyletIoC\StyletIoCFactoryTests.cs" />
<Compile Include="StyletIoC\StyletIoCGetAllTests.cs" />
<Compile Include="StyletIoC\StyletIoCGetSingleKeyedTests.cs" />
<Compile Include="StyletIoC\StyletIoCGetSingleTests.cs" />
<Compile Include="StyletIoC\UnboundGenericTests.cs" />
<Compile Include="StyletIoC\StyletIoCUnboundGenericTests.cs" />
</ItemGroup>
<ItemGroup>
<Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />