mirror of https://github.com/AMT-Cheif/Stylet.git
Fix BuildUp, and add unit tests
This commit is contained in:
parent
27594d2fdb
commit
9a18af55c9
|
@ -26,6 +26,7 @@ namespace Stylet
|
||||||
T Get<T>(string key = null);
|
T Get<T>(string key = null);
|
||||||
IEnumerable<object> GetAll(Type type, string key = null);
|
IEnumerable<object> GetAll(Type type, string key = null);
|
||||||
IEnumerable<T> GetAll<T>(string key = null);
|
IEnumerable<T> GetAll<T>(string key = null);
|
||||||
|
void BuildUp(object item);
|
||||||
}
|
}
|
||||||
|
|
||||||
public interface IStyletIoCBindTo
|
public interface IStyletIoCBindTo
|
||||||
|
@ -53,6 +54,7 @@ namespace Stylet
|
||||||
private ConcurrentDictionary<TypeKey, IRegistration> getAllRegistrations = new ConcurrentDictionary<TypeKey, IRegistration>();
|
private ConcurrentDictionary<TypeKey, IRegistration> getAllRegistrations = new ConcurrentDictionary<TypeKey, IRegistration>();
|
||||||
// The list object is used for locking it
|
// The list object is used for locking it
|
||||||
private ConcurrentDictionary<TypeKey, List<UnboundGeneric>> unboundGenerics = new ConcurrentDictionary<TypeKey, List<UnboundGeneric>>();
|
private ConcurrentDictionary<TypeKey, List<UnboundGeneric>> unboundGenerics = new ConcurrentDictionary<TypeKey, List<UnboundGeneric>>();
|
||||||
|
private ConcurrentDictionary<Type, BuilderUpper> builderUppers = new ConcurrentDictionary<Type, BuilderUpper>();
|
||||||
|
|
||||||
|
|
||||||
private ModuleBuilder factoryBuilder;
|
private ModuleBuilder factoryBuilder;
|
||||||
|
@ -166,6 +168,13 @@ namespace Stylet
|
||||||
return this.GetAll(typeof(T), key).Cast<T>();
|
return this.GetAll(typeof(T), key).Cast<T>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void BuildUp(object item)
|
||||||
|
{
|
||||||
|
var builderUpper = this.GetBuilderUpper(item.GetType());
|
||||||
|
builderUpper.GetImplementor(this)(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
private bool CanResolve(TypeKey typeKey)
|
private bool CanResolve(TypeKey typeKey)
|
||||||
{
|
{
|
||||||
IRegistrationCollection registrations;
|
IRegistrationCollection registrations;
|
||||||
|
@ -283,7 +292,6 @@ namespace Stylet
|
||||||
IRegistrationCollection registrations;
|
IRegistrationCollection registrations;
|
||||||
|
|
||||||
// Try to get registrations. If there are none, see if we can add some from unbound generics
|
// Try to get registrations. If there are none, see if we can add some from unbound generics
|
||||||
// If we still fail, try searching the 'get all' types
|
|
||||||
if (!this.registrations.TryGetValue(typeKey, out registrations) &&
|
if (!this.registrations.TryGetValue(typeKey, out registrations) &&
|
||||||
!this.TryCreateGenericTypesForUnboundGeneric(typeKey, out registrations))
|
!this.TryCreateGenericTypesForUnboundGeneric(typeKey, out registrations))
|
||||||
{
|
{
|
||||||
|
@ -431,6 +439,11 @@ namespace Stylet
|
||||||
return actualType;
|
return actualType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private BuilderUpper GetBuilderUpper(Type type)
|
||||||
|
{
|
||||||
|
return this.builderUppers.GetOrAdd(type, x => new BuilderUpper(type));
|
||||||
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region BindTo
|
#region BindTo
|
||||||
|
@ -906,20 +919,22 @@ namespace Stylet
|
||||||
this.type = type;
|
this.type = type;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Expression GetExpression(StyletIoC container, ParameterExpression inputParameterExpression)
|
public Expression GetExpression(StyletIoC container, Expression inputParameterExpression)
|
||||||
{
|
{
|
||||||
var expressions = this.type.GetFields().Select(x => this.ExpressionForMember(container, inputParameterExpression, x, x.FieldType))
|
var expressions = this.type.GetFields(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance).Select(x => this.ExpressionForMember(container, inputParameterExpression, x, x.FieldType))
|
||||||
.Concat(this.type.GetProperties().Select(x => this.ExpressionForMember(container, inputParameterExpression, x, x.PropertyType)))
|
.Concat(this.type.GetProperties(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance).Select(x => this.ExpressionForMember(container, inputParameterExpression, x, x.PropertyType)))
|
||||||
.Where(x => x != null);
|
.Where(x => x != null);
|
||||||
|
|
||||||
// Sadly, we can't cache this expression (I think), as it relies on the inputParameterExpression
|
// Sadly, we can't cache this expression (I think), as it relies on the inputParameterExpression
|
||||||
// which is likely to change between calls
|
// which is likely to change between calls
|
||||||
// This isn't so bad, so we'll (probably) only need to call this at most twice - once for building up the type on creation,
|
// This isn't so bad, so we'll (probably) only need to call this at most twice - once for building up the type on creation,
|
||||||
// and once for creating the implemtor (which is used in BuildUp())
|
// and once for creating the implemtor (which is used in BuildUp())
|
||||||
|
if (!expressions.Any())
|
||||||
|
return Expression.Empty();
|
||||||
return Expression.Block(expressions);
|
return Expression.Block(expressions);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Expression ExpressionForMember(StyletIoC container, ParameterExpression objExpression, MemberInfo member, Type memberType)
|
private Expression ExpressionForMember(StyletIoC container, Expression objExpression, MemberInfo member, Type memberType)
|
||||||
{
|
{
|
||||||
var attribute = member.GetCustomAttribute<InjectAttribute>(true);
|
var attribute = member.GetCustomAttribute<InjectAttribute>(true);
|
||||||
if (attribute == null)
|
if (attribute == null)
|
||||||
|
@ -936,8 +951,9 @@ namespace Stylet
|
||||||
if (this.implementor != null)
|
if (this.implementor != null)
|
||||||
return this.implementor;
|
return this.implementor;
|
||||||
|
|
||||||
var parameterExpression = Expression.Parameter(this.type, "inputParameter");
|
var parameterExpression = Expression.Parameter(typeof(object), "inputParameter");
|
||||||
this.implementor = Expression.Lambda<Action<object>>(this.GetExpression(container, parameterExpression), parameterExpression).Compile();
|
var typedParameterExpression = Expression.Convert(parameterExpression, this.type);
|
||||||
|
this.implementor = Expression.Lambda<Action<object>>(this.GetExpression(container, typedParameterExpression), parameterExpression).Compile();
|
||||||
return this.implementor;
|
return this.implementor;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1024,7 +1040,7 @@ namespace Stylet
|
||||||
public StyletIoCCreateFactoryException(string message, Exception innerException) : base(message, innerException) { }
|
public StyletIoCCreateFactoryException(string message, Exception innerException) : base(message, innerException) { }
|
||||||
}
|
}
|
||||||
|
|
||||||
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Constructor | AttributeTargets.Parameter, Inherited = false, AllowMultiple = false)]
|
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Constructor | AttributeTargets.Parameter | AttributeTargets.Field | AttributeTargets.Property, Inherited = false, AllowMultiple = false)]
|
||||||
public sealed class InjectAttribute : Attribute
|
public sealed class InjectAttribute : Attribute
|
||||||
{
|
{
|
||||||
public InjectAttribute()
|
public InjectAttribute()
|
||||||
|
|
|
@ -0,0 +1,121 @@
|
||||||
|
using NUnit.Framework;
|
||||||
|
using Stylet;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace StyletUnitTests
|
||||||
|
{
|
||||||
|
[TestFixture]
|
||||||
|
public class StyletIoCBuildUpTests
|
||||||
|
{
|
||||||
|
class C1 { }
|
||||||
|
interface I2 { }
|
||||||
|
class C2 : I2 { }
|
||||||
|
|
||||||
|
class Subject1
|
||||||
|
{
|
||||||
|
public C1 Ignored;
|
||||||
|
|
||||||
|
[Inject]
|
||||||
|
public C1 C1;
|
||||||
|
}
|
||||||
|
|
||||||
|
class Subject2
|
||||||
|
{
|
||||||
|
[Inject]
|
||||||
|
private C1 c1;
|
||||||
|
public C1 GetC1() { return this.c1; }
|
||||||
|
}
|
||||||
|
|
||||||
|
class Subject3
|
||||||
|
{
|
||||||
|
[Inject]
|
||||||
|
public C1 C1 { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
class Subject4
|
||||||
|
{
|
||||||
|
[Inject]
|
||||||
|
public C1 C11 { get; private set; }
|
||||||
|
[Inject]
|
||||||
|
private C1 C12 { get; set; }
|
||||||
|
|
||||||
|
public C1 GetC11() { return this.C11; }
|
||||||
|
public C1 GetC12() { return this.C12; }
|
||||||
|
}
|
||||||
|
|
||||||
|
class Subject5
|
||||||
|
{
|
||||||
|
[Inject("key")]
|
||||||
|
public C1 C1;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void BuildsUpPublicFields()
|
||||||
|
{
|
||||||
|
var ioc = new StyletIoC();
|
||||||
|
ioc.Bind<C1>().ToSelf();
|
||||||
|
var subject = new Subject1();
|
||||||
|
ioc.BuildUp(subject);
|
||||||
|
|
||||||
|
Assert.IsInstanceOf<C1>(subject.C1);
|
||||||
|
Assert.IsNull(subject.Ignored);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void BuildsUpPrivateFields()
|
||||||
|
{
|
||||||
|
var ioc = new StyletIoC();
|
||||||
|
ioc.Bind<C1>().ToSelf();
|
||||||
|
var subject = new Subject2();
|
||||||
|
ioc.BuildUp(subject);
|
||||||
|
|
||||||
|
Assert.IsInstanceOf<C1>(subject.GetC1());
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void BuildsUpPublicProperties()
|
||||||
|
{
|
||||||
|
var ioc = new StyletIoC();
|
||||||
|
ioc.Bind<C1>().ToSelf();
|
||||||
|
var subject = new Subject3();
|
||||||
|
ioc.BuildUp(subject);
|
||||||
|
|
||||||
|
Assert.IsInstanceOf<C1>(subject.C1);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void BuildsUpPrivateProperties()
|
||||||
|
{
|
||||||
|
var ioc = new StyletIoC();
|
||||||
|
ioc.Bind<C1>().ToSelf();
|
||||||
|
var subject = new Subject4();
|
||||||
|
ioc.BuildUp(subject);
|
||||||
|
|
||||||
|
Assert.IsInstanceOf<C1>(subject.GetC11());
|
||||||
|
Assert.IsInstanceOf<C1>(subject.GetC12());
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void RespectsKeys()
|
||||||
|
{
|
||||||
|
var ioc = new StyletIoC();
|
||||||
|
ioc.Bind<C1>().ToSelf("key");
|
||||||
|
var subject = new Subject5();
|
||||||
|
ioc.BuildUp(subject);
|
||||||
|
|
||||||
|
Assert.IsInstanceOf<C1>(subject.C1);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void ThrowsIfCanNotResolve()
|
||||||
|
{
|
||||||
|
var ioc = new StyletIoC();
|
||||||
|
var subject = new Subject1();
|
||||||
|
Assert.Throws<StyletIoCRegistrationException>(() => ioc.BuildUp(subject));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -48,6 +48,7 @@
|
||||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||||
<Compile Include="StyletIoCAutobindingTests.cs" />
|
<Compile Include="StyletIoCAutobindingTests.cs" />
|
||||||
<Compile Include="StyletIoCBindingChecksTests.cs" />
|
<Compile Include="StyletIoCBindingChecksTests.cs" />
|
||||||
|
<Compile Include="StyletIoCBuildUpTests.cs" />
|
||||||
<Compile Include="StyletIoCConstructorInjectionTests.cs" />
|
<Compile Include="StyletIoCConstructorInjectionTests.cs" />
|
||||||
<Compile Include="StyletIoCFactoryTests.cs" />
|
<Compile Include="StyletIoCFactoryTests.cs" />
|
||||||
<Compile Include="StyletIoCGetAllTests.cs" />
|
<Compile Include="StyletIoCGetAllTests.cs" />
|
||||||
|
|
Loading…
Reference in New Issue