mirror of https://github.com/AMT-Cheif/Stylet.git
WIP: Support 'And' to bind multiple services to type
This commit is contained in:
parent
447f68f1f0
commit
498597c0a6
|
@ -0,0 +1,15 @@
|
|||
using System;
|
||||
|
||||
namespace StyletIoC.Creation
|
||||
{
|
||||
public class BuilderTypeKey
|
||||
{
|
||||
public Type Type { get; set; }
|
||||
public string Key { get; set; }
|
||||
|
||||
public BuilderTypeKey(Type type)
|
||||
{
|
||||
this.Type = type;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,4 +1,5 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq.Expressions;
|
||||
|
||||
namespace StyletIoC.Creation
|
||||
|
@ -7,11 +8,10 @@ namespace StyletIoC.Creation
|
|||
/// Delegate used to create an IRegistration
|
||||
/// </summary>
|
||||
/// <param name="parentContext">Context on which this registration will be created</param>
|
||||
/// <param name="serviceType">Service type for this registration</param>
|
||||
/// <param name="serviceTypes">Service types and keys for this registration</param>
|
||||
/// <param name="creator">ICreator used by the IRegistration to create new instances</param>
|
||||
/// <param name="key">Key associated with the registration</param>
|
||||
/// <returns>A new IRegistration</returns>
|
||||
public delegate IRegistration RegistrationFactory(IRegistrationContext parentContext, Type serviceType, ICreator creator, string key);
|
||||
public delegate IRegistration RegistrationFactory(IRegistrationContext parentContext, List<BuilderTypeKey> serviceTypes, ICreator creator);
|
||||
|
||||
/// <summary>
|
||||
/// An IRegistration is responsible to returning an appropriate (new or cached) instanced of a type, or an expression doing the same.
|
||||
|
|
|
@ -1,25 +1,33 @@
|
|||
using StyletIoC.Internal.Creators;
|
||||
using StyletIoC.Internal.Registrations;
|
||||
using System;
|
||||
using StyletIoC.Creation;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace StyletIoC.Internal.Builders
|
||||
{
|
||||
internal class BuilderAbstractFactoryBinding : BuilderBindingBase
|
||||
{
|
||||
public BuilderAbstractFactoryBinding(Type serviceType)
|
||||
: base(serviceType)
|
||||
public BuilderAbstractFactoryBinding(List<BuilderTypeKey> serviceTypes)
|
||||
: base(serviceTypes)
|
||||
{
|
||||
if (serviceType.IsGenericTypeDefinition)
|
||||
throw new StyletIoCRegistrationException(String.Format("Unbound generic type {0} can't be used as an abstract factory", serviceType.GetDescription()));
|
||||
foreach (var serviceType in this.ServiceTypes)
|
||||
{
|
||||
if (serviceType.Type.IsGenericTypeDefinition)
|
||||
throw new StyletIoCRegistrationException(String.Format("Unbound generic type {0} can't be used as an abstract factory", serviceType.Type.GetDescription()));
|
||||
}
|
||||
}
|
||||
|
||||
public override void Build(Container container)
|
||||
{
|
||||
var factoryType = container.GetFactoryForType(this.ServiceType);
|
||||
var creator = new AbstractFactoryCreator(factoryType);
|
||||
var registration = new TransientRegistration(creator);
|
||||
foreach (var serviceType in this.ServiceTypes)
|
||||
{
|
||||
var factoryType = container.GetFactoryForType(serviceType.Type);
|
||||
var creator = new AbstractFactoryCreator(factoryType);
|
||||
var registration = new TransientRegistration(creator);
|
||||
|
||||
container.AddRegistration(new TypeKey(this.ServiceType.TypeHandle, this.Key), registration);
|
||||
container.AddRegistration(new TypeKey(serviceType.Type.TypeHandle, serviceType.Key), registration);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,25 +9,24 @@ namespace StyletIoC.Internal.Builders
|
|||
internal class BuilderBindTo : IBindTo
|
||||
{
|
||||
private readonly Func<IEnumerable<Assembly>, string, IEnumerable<Assembly>> getAssemblies;
|
||||
public Type ServiceType { get; private set; }
|
||||
public List<BuilderTypeKey> ServiceTypes { get; private set; }
|
||||
private BuilderBindingBase builderBinding;
|
||||
public bool IsWeak { get { return this.builderBinding.IsWeak; } }
|
||||
public string Key { get { return this.builderBinding.Key; } }
|
||||
|
||||
public BuilderBindTo(Type serviceType, Func<IEnumerable<Assembly>, string, IEnumerable<Assembly>> getAssemblies)
|
||||
{
|
||||
this.ServiceType = serviceType;
|
||||
this.ServiceTypes = new List<BuilderTypeKey>() { new BuilderTypeKey(serviceType) };
|
||||
this.getAssemblies = getAssemblies;
|
||||
}
|
||||
|
||||
public IInScopeOrWithKeyOrAsWeakBinding ToSelf()
|
||||
{
|
||||
return this.To(this.ServiceType);
|
||||
return this.To(this.ServiceTypes);
|
||||
}
|
||||
|
||||
public IInScopeOrWithKeyOrAsWeakBinding To(Type implementationType)
|
||||
{
|
||||
this.builderBinding = new BuilderTypeBinding(this.ServiceType, implementationType);
|
||||
this.builderBinding = new BuilderTypeBinding(this.ServiceTypes, implementationType);
|
||||
return this.builderBinding;
|
||||
}
|
||||
|
||||
|
@ -38,25 +37,25 @@ namespace StyletIoC.Internal.Builders
|
|||
|
||||
public IInScopeOrWithKeyOrAsWeakBinding ToFactory<TImplementation>(Func<IRegistrationContext, TImplementation> factory)
|
||||
{
|
||||
this.builderBinding = new BuilderFactoryBinding<TImplementation>(this.ServiceType, factory);
|
||||
this.builderBinding = new BuilderFactoryBinding<TImplementation>(this.ServiceTypes, factory);
|
||||
return this.builderBinding;
|
||||
}
|
||||
|
||||
public IWithKeyOrAsWeakBinding ToInstance(object instance)
|
||||
{
|
||||
this.builderBinding = new BuilderInstanceBinding(this.ServiceType, instance);
|
||||
this.builderBinding = new BuilderInstanceBinding(this.ServiceTypes, instance);
|
||||
return this.builderBinding;
|
||||
}
|
||||
|
||||
public IWithKeyOrAsWeakBinding ToAbstractFactory()
|
||||
{
|
||||
this.builderBinding = new BuilderAbstractFactoryBinding(this.ServiceType);
|
||||
this.builderBinding = new BuilderAbstractFactoryBinding(this.ServiceTypes);
|
||||
return this.builderBinding;
|
||||
}
|
||||
|
||||
public IInScopeOrWithKeyOrAsWeakBinding ToAllImplementations(IEnumerable<Assembly> assemblies)
|
||||
{
|
||||
this.builderBinding = new BuilderToAllImplementationsBinding(this.ServiceType, this.getAssemblies(assemblies, "ToAllImplementations"));
|
||||
this.builderBinding = new BuilderToAllImplementationsBinding(this.ServiceTypes, this.getAssemblies(assemblies, "ToAllImplementations"));
|
||||
return this.builderBinding;
|
||||
}
|
||||
|
||||
|
|
|
@ -3,22 +3,22 @@ using StyletIoC.Internal.Creators;
|
|||
using StyletIoC.Internal.Registrations;
|
||||
using System;
|
||||
using System.Reflection;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace StyletIoC.Internal.Builders
|
||||
{
|
||||
internal abstract class BuilderBindingBase : IInScopeOrWithKeyOrAsWeakBinding, IWithKeyOrAsWeakBinding
|
||||
{
|
||||
protected Type ServiceType { get; set; }
|
||||
protected List<BuilderTypeKey> ServiceTypes { get; private set; }
|
||||
protected RegistrationFactory RegistrationFactory { get; set; }
|
||||
public string Key { get; protected set; }
|
||||
public bool IsWeak { get; protected set; }
|
||||
|
||||
protected BuilderBindingBase(Type serviceType)
|
||||
protected BuilderBindingBase(List<BuilderTypeKey> serviceTypes)
|
||||
{
|
||||
this.ServiceType = serviceType;
|
||||
this.ServiceTypes = serviceTypes;
|
||||
|
||||
// Default is transient
|
||||
this.RegistrationFactory = (ctx, service, creator, key) => new TransientRegistration(creator);
|
||||
this.RegistrationFactory = (ctx, services, creator) => new TransientRegistration(creator);
|
||||
}
|
||||
|
||||
public IAsWeakBinding WithRegistrationFactory(RegistrationFactory registrationFactory)
|
||||
|
@ -35,19 +35,25 @@ namespace StyletIoC.Internal.Builders
|
|||
/// <returns>Fluent interface to continue configuration</returns>
|
||||
public IAsWeakBinding InSingletonScope()
|
||||
{
|
||||
return this.WithRegistrationFactory((ctx, serviceType, creator, key) => new SingletonRegistration(ctx, creator));
|
||||
return this.WithRegistrationFactory((ctx, serviceTypes, creator) => new SingletonRegistration(ctx, creator));
|
||||
}
|
||||
|
||||
public IInScopeOrAsWeakBinding WithKey(string key)
|
||||
{
|
||||
this.Key = key;
|
||||
this.ServiceTypes[this.ServiceTypes.Count - 1].Key = key;
|
||||
return this;
|
||||
}
|
||||
|
||||
protected void EnsureType(Type implementationType, Type serviceType = null, bool assertImplementation = true)
|
||||
protected void EnsureTypeAgainstServiceTypes(Type implementationType, bool assertImplementation = true)
|
||||
{
|
||||
serviceType = serviceType ?? this.ServiceType;
|
||||
foreach (var serviceType in this.ServiceTypes)
|
||||
{
|
||||
EnsureType(implementationType, serviceType.Type, assertImplementation);
|
||||
}
|
||||
}
|
||||
|
||||
protected static void EnsureType(Type implementationType, Type serviceType, bool assertImplementation = true)
|
||||
{
|
||||
if (assertImplementation && (!implementationType.IsClass || implementationType.IsAbstract))
|
||||
throw new StyletIoCRegistrationException(String.Format("Type {0} is not a concrete class, and so can't be used to implemented service {1}", implementationType.GetDescription(), serviceType.GetDescription()));
|
||||
|
||||
|
@ -73,34 +79,40 @@ namespace StyletIoC.Internal.Builders
|
|||
throw new StyletIoCRegistrationException(String.Format("Type {0} does not implement service {1}", implementationType.GetDescription(), serviceType.GetDescription()));
|
||||
}
|
||||
|
||||
// Convenience...
|
||||
protected void BindImplementationToService(Container container, Type implementationType, Type serviceType = null)
|
||||
protected void BindImplementationToServices(Container container, Type implementationType)
|
||||
{
|
||||
serviceType = serviceType ?? this.ServiceType;
|
||||
foreach (var serviceType in this.ServiceTypes)
|
||||
{
|
||||
this.BindImplementationToSpecificService(container, implementationType, serviceType.Type, serviceType.Key);
|
||||
}
|
||||
}
|
||||
|
||||
// Convenience...
|
||||
protected void BindImplementationToSpecificService(Container container, Type implementationType, Type serviceType, string key)
|
||||
{
|
||||
if (serviceType.IsGenericTypeDefinition)
|
||||
{
|
||||
var unboundGeneric = new UnboundGeneric(serviceType, implementationType, container, this.RegistrationFactory);
|
||||
container.AddUnboundGeneric(new TypeKey(serviceType.TypeHandle, this.Key), unboundGeneric);
|
||||
container.AddUnboundGeneric(new TypeKey(serviceType.TypeHandle, key), unboundGeneric);
|
||||
}
|
||||
else
|
||||
{
|
||||
var creator = new TypeCreator(implementationType, container);
|
||||
var registration = this.CreateRegistration(container, creator);
|
||||
|
||||
container.AddRegistration(new TypeKey(serviceType.TypeHandle, this.Key ?? creator.AttributeKey), registration);
|
||||
container.AddRegistration(new TypeKey(serviceType.TypeHandle, key ?? creator.AttributeKey), registration);
|
||||
}
|
||||
}
|
||||
|
||||
// Convenience...
|
||||
protected IRegistration CreateRegistration(IRegistrationContext registrationContext, ICreator creator)
|
||||
{
|
||||
return this.RegistrationFactory(registrationContext, this.ServiceType, creator, this.Key);
|
||||
return this.RegistrationFactory(registrationContext, this.ServiceTypes, creator);
|
||||
}
|
||||
|
||||
IAsWeakBinding IWithKeyOrAsWeakBinding.WithKey(string key)
|
||||
{
|
||||
this.Key = key;
|
||||
this.ServiceTypes[this.ServiceTypes.Count - 1].Key = key;
|
||||
return this;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
using StyletIoC.Creation;
|
||||
using StyletIoC.Internal.Creators;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace StyletIoC.Internal.Builders
|
||||
{
|
||||
|
@ -8,12 +9,15 @@ namespace StyletIoC.Internal.Builders
|
|||
{
|
||||
private readonly Func<IRegistrationContext, TImplementation> factory;
|
||||
|
||||
public BuilderFactoryBinding(Type serviceType, Func<IRegistrationContext, TImplementation> factory)
|
||||
: base(serviceType)
|
||||
public BuilderFactoryBinding(List<BuilderTypeKey> serviceTypes, Func<IRegistrationContext, TImplementation> factory)
|
||||
: base(serviceTypes)
|
||||
{
|
||||
if (this.ServiceType.IsGenericTypeDefinition)
|
||||
throw new StyletIoCRegistrationException(String.Format("A factory cannot be used to implement unbound generic type {0}", this.ServiceType.GetDescription()));
|
||||
this.EnsureType(typeof(TImplementation), assertImplementation: false);
|
||||
foreach (var serviceType in this.ServiceTypes)
|
||||
{
|
||||
if (serviceType.Type.IsGenericTypeDefinition)
|
||||
throw new StyletIoCRegistrationException(String.Format("A factory cannot be used to implement unbound generic type {0}", serviceType.Type.GetDescription()));
|
||||
this.EnsureTypeAgainstServiceTypes(typeof(TImplementation), assertImplementation: false);
|
||||
}
|
||||
this.factory = factory;
|
||||
}
|
||||
|
||||
|
@ -22,7 +26,10 @@ namespace StyletIoC.Internal.Builders
|
|||
var creator = new FactoryCreator<TImplementation>(this.factory, container);
|
||||
var registration = this.CreateRegistration(container, creator);
|
||||
|
||||
container.AddRegistration(new TypeKey(this.ServiceType.TypeHandle, this.Key), registration);
|
||||
foreach (var serviceType in this.ServiceTypes)
|
||||
{
|
||||
container.AddRegistration(new TypeKey(serviceType.Type.TypeHandle, serviceType.Key), registration);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using StyletIoC.Creation;
|
||||
using StyletIoC.Internal.Creators;
|
||||
|
||||
namespace StyletIoC.Internal.Builders
|
||||
|
@ -7,10 +9,10 @@ namespace StyletIoC.Internal.Builders
|
|||
{
|
||||
private readonly object instance;
|
||||
|
||||
public BuilderInstanceBinding(Type serviceType, object instance)
|
||||
: base(serviceType)
|
||||
public BuilderInstanceBinding(List<BuilderTypeKey> serviceTypes, object instance)
|
||||
: base(serviceTypes)
|
||||
{
|
||||
this.EnsureType(instance.GetType(), assertImplementation: false);
|
||||
this.EnsureTypeAgainstServiceTypes(instance.GetType(), assertImplementation: false);
|
||||
this.instance = instance;
|
||||
}
|
||||
|
||||
|
@ -19,7 +21,10 @@ namespace StyletIoC.Internal.Builders
|
|||
var creator = new InstanceCreator(this.instance);
|
||||
var registration = this.CreateRegistration(container, creator);
|
||||
|
||||
container.AddRegistration(new TypeKey(this.ServiceType.TypeHandle, this.Key), registration);
|
||||
foreach (var serviceType in this.ServiceTypes)
|
||||
{
|
||||
container.AddRegistration(new TypeKey(serviceType.Type.TypeHandle, serviceType.Key), registration);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@ using System.Collections.Generic;
|
|||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using StyletIoC.Creation;
|
||||
|
||||
namespace StyletIoC.Internal.Builders
|
||||
{
|
||||
|
@ -10,8 +11,8 @@ namespace StyletIoC.Internal.Builders
|
|||
{
|
||||
private readonly IEnumerable<Assembly> assemblies;
|
||||
|
||||
public BuilderToAllImplementationsBinding(Type serviceType, IEnumerable<Assembly> assemblies)
|
||||
: base(serviceType)
|
||||
public BuilderToAllImplementationsBinding(List<BuilderTypeKey> serviceTypes, IEnumerable<Assembly> assemblies)
|
||||
: base(serviceTypes)
|
||||
{
|
||||
this.assemblies = assemblies;
|
||||
}
|
||||
|
@ -19,7 +20,7 @@ namespace StyletIoC.Internal.Builders
|
|||
public override void Build(Container container)
|
||||
{
|
||||
var candidates = from type in this.assemblies.Distinct().SelectMany(x => x.GetTypes())
|
||||
let baseType = type.GetBaseTypesAndInterfaces().FirstOrDefault(x => x == this.ServiceType || (x.IsGenericType && x.GetGenericTypeDefinition() == this.ServiceType))
|
||||
let baseType = type.GetBaseTypesAndInterfaces().FirstOrDefault(x => x == this.ServiceTypes || (x.IsGenericType && x.GetGenericTypeDefinition() == this.ServiceTypes))
|
||||
where baseType != null
|
||||
select new { Type = type, Base = baseType.ContainsGenericParameters ? baseType.GetGenericTypeDefinition() : baseType };
|
||||
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using StyletIoC.Creation;
|
||||
|
||||
namespace StyletIoC.Internal.Builders
|
||||
{
|
||||
|
@ -6,16 +8,16 @@ namespace StyletIoC.Internal.Builders
|
|||
{
|
||||
private readonly Type implementationType;
|
||||
|
||||
public BuilderTypeBinding(Type serviceType, Type implementationType)
|
||||
: base(serviceType)
|
||||
public BuilderTypeBinding(List<BuilderTypeKey> serviceTypes, Type implementationType)
|
||||
: base(serviceTypes)
|
||||
{
|
||||
this.EnsureType(implementationType);
|
||||
this.EnsureTypeAgainstServiceTypes(implementationType);
|
||||
this.implementationType = implementationType;
|
||||
}
|
||||
|
||||
public override void Build(Container container)
|
||||
{
|
||||
this.BindImplementationToService(container, this.implementationType);
|
||||
this.BindImplementationToServices(container, this.implementationType);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue