mirror of https://github.com/AMT-Cheif/Stylet.git
Start getting towards something that works...
This commit is contained in:
parent
498597c0a6
commit
bd18b94e82
|
@ -55,8 +55,10 @@
|
|||
<Compile Include="Logging\ILogger.cs" />
|
||||
<Compile Include="Logging\NullLogger.cs" />
|
||||
<Compile Include="Logging\TraceLogger.cs" />
|
||||
<Compile Include="StyletIoC\Creation\BuilderTypeKey.cs" />
|
||||
<Compile Include="StyletIoC\Creation\ICreator.cs" />
|
||||
<Compile Include="StyletIoC\Creation\IRegistration.cs" />
|
||||
<Compile Include="StyletIoC\FluentInterface.cs" />
|
||||
<Compile Include="StyletIoC\Internal\Builders\BuilderAbstractFactoryBinding.cs" />
|
||||
<Compile Include="StyletIoC\Internal\Builders\BuilderBindingBase.cs" />
|
||||
<Compile Include="StyletIoC\Internal\Builders\BuilderBindTo.cs" />
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
namespace StyletIoC.Creation
|
||||
{
|
||||
public class BuilderTypeKey
|
||||
public class BuilderTypeKey : IEquatable<BuilderTypeKey>
|
||||
{
|
||||
public Type Type { get; set; }
|
||||
public string Key { get; set; }
|
||||
|
@ -11,5 +11,35 @@ namespace StyletIoC.Creation
|
|||
{
|
||||
this.Type = type;
|
||||
}
|
||||
|
||||
public BuilderTypeKey(Type type, string key)
|
||||
{
|
||||
this.Type = type;
|
||||
this.Key = key;
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
return base.Equals(obj as BuilderTypeKey);
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
unchecked
|
||||
{
|
||||
int hash = 17;
|
||||
hash = hash * 23 + this.Type.GetHashCode();
|
||||
if (this.Key != null)
|
||||
hash = hash * 23 + this.Key.GetHashCode();
|
||||
return hash;
|
||||
}
|
||||
}
|
||||
|
||||
public bool Equals(BuilderTypeKey other)
|
||||
{
|
||||
return other != null &&
|
||||
this.Type == other.Type &&
|
||||
other.Key == this.Key;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,166 @@
|
|||
using StyletIoC.Creation;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
|
||||
namespace StyletIoC
|
||||
{
|
||||
/// <summary>
|
||||
/// Interface for selecting what to bind a service to.
|
||||
/// Call StyletIoCBuilder.Bind(..) to get an instance of this
|
||||
/// </summary>
|
||||
public interface IBindTo : IToAnyService, IWithKeyOrAndOrToMultipleServices, IWithKeyOrToMulipleServices
|
||||
{
|
||||
}
|
||||
|
||||
public interface IToMultipleServices
|
||||
{
|
||||
/// <summary>
|
||||
/// Bind the specified service to another type which implements that service. E.g. builder.Bind{IMyClass}().To(typeof(MyClass)), and request an IMyClass: you'll get a MyClass.
|
||||
/// </summary>
|
||||
/// <param name="implementationType">Type to bind the service to</param>
|
||||
/// <returns>Fluent interface to continue configuration</returns>
|
||||
IInScopeOrWithKeyOrAsWeakBinding To(Type implementationType);
|
||||
|
||||
/// <summary>
|
||||
/// Bind the specified service to another type which implements that service. E.g. builder.Bind{IMyClass}().To{MyClass}(), and request an IMyClass: you'll get a MyClass.
|
||||
/// </summary>
|
||||
/// <typeparam name="TImplementation">Type to bind the service to</typeparam>
|
||||
/// <returns>Fluent interface to continue configuration</returns>
|
||||
IInScopeOrWithKeyOrAsWeakBinding To<TImplementation>();
|
||||
|
||||
/// <summary>
|
||||
/// Bind the specified service to a factory delegate, which will be called when an instance is required. E.g. ...ToFactory(c => new MyClass(c.Get{Dependency}(), "foo"))
|
||||
/// </summary>
|
||||
/// <typeparam name="TImplementation">Type returned by the factory delegate. Must implement the service</typeparam>
|
||||
/// <param name="factory">Factory delegate to bind got</param>
|
||||
/// <returns>Fluent interface to continue configuration</returns>
|
||||
IInScopeOrWithKeyOrAsWeakBinding ToFactory<TImplementation>(Func<IRegistrationContext, TImplementation> factory);
|
||||
|
||||
/// <summary>
|
||||
/// Bind the specified service to the given untyped instance
|
||||
/// </summary>
|
||||
/// <param name="instance">Instance to use</param>
|
||||
/// <returns>Fluent interface to continue configuration</returns>
|
||||
IWithKeyOrAsWeakBinding ToInstance(object instance);
|
||||
}
|
||||
|
||||
public interface IToAnyService : IToMultipleServices
|
||||
{
|
||||
/// <summary>
|
||||
/// Bind the specified service to itself - if you self-bind MyClass, and request an instance of MyClass, you'll get an instance of MyClass.
|
||||
/// </summary>
|
||||
/// <returns>Fluent interface to continue configuration</returns>
|
||||
IInScopeOrWithKeyOrAsWeakBinding ToSelf();
|
||||
|
||||
/// <summary>
|
||||
/// If the service is an interface with a number of methods which return other types, generate an implementation of that abstract factory and bind it to the interface.
|
||||
/// </summary>
|
||||
/// <returns>Fluent interface to continue configuration</returns>
|
||||
IWithKeyOrAsWeakBinding ToAbstractFactory();
|
||||
|
||||
/// <summary>
|
||||
/// Discover all implementations of the service in the specified assemblies / the current assembly, and bind those to the service
|
||||
/// </summary>
|
||||
/// <param name="assemblies">Assemblies to search. If empty / null, searches the current assembly</param>
|
||||
/// <returns>Fluent interface to continue configuration</returns>
|
||||
IInScopeOrWithKeyOrAsWeakBinding ToAllImplementations(IEnumerable<Assembly> assemblies);
|
||||
|
||||
/// <summary>
|
||||
/// Discover all implementations of the service in the specified assemblies / the current assembly, and bind those to the service
|
||||
/// </summary>
|
||||
/// <param name="assemblies">Assemblies to search. If empty / null, searches the current assembly</param>
|
||||
/// <returns>Fluent interface to continue configuration</returns>
|
||||
IInScopeOrWithKeyOrAsWeakBinding ToAllImplementations(params Assembly[] assemblies);
|
||||
}
|
||||
|
||||
public interface IAndTo
|
||||
{
|
||||
IWithKeyOrAndOrToMultipleServices And(Type serviceType);
|
||||
IWithKeyOrAndOrToMultipleServices And<TService>();
|
||||
}
|
||||
|
||||
public interface IWithKeyOrToMulipleServices : IToMultipleServices
|
||||
{
|
||||
IAndOrToMultipleServices WithKey(string key);
|
||||
}
|
||||
|
||||
public interface IAndOrToMultipleServices : IToMultipleServices, IAndTo
|
||||
{
|
||||
}
|
||||
|
||||
public interface IWithKeyOrAndOrToMultipleServices : IWithKeyOrToMulipleServices, IAndTo
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Fluent interface on which AsWeakBinding can be called
|
||||
/// </summary>
|
||||
public interface IAsWeakBinding
|
||||
{
|
||||
/// <summary>
|
||||
/// Mark the binding as weak
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// When the container is built, each collection of registrations for each Type+key combination is examined.
|
||||
/// If only weak bindings exist, then all bindings are built into the container.
|
||||
/// If any normal bindings exist, then all weak bindings are ignored, and only the normal bindings are built into the container.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// This is very useful for integration StyletIoC into a framework. The framework can add default bindings for services as
|
||||
/// weak bindings, and the user can use normal bindings. If the user does specify a binding, then this will override
|
||||
/// the binding set by the framework.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// This is also used by AutoBind when self-binding concrete types, for the sme reason.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
void AsWeakBinding();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Fluent interface on which WithKey or AsWeakBinding can be called
|
||||
/// </summary>
|
||||
public interface IWithKeyOrAsWeakBinding : IAsWeakBinding
|
||||
{
|
||||
/// <summary>
|
||||
/// Associate a key with this binding. Requests for the service will have to specify this key to retrieve the result of this binding
|
||||
/// </summary>
|
||||
/// <param name="key">Key to associate with this binding</param>
|
||||
/// <returns>Fluent interface to continue configuration</returns>
|
||||
IAsWeakBinding WithKey(string key);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Fluent interface on which methods to modify the scope can be called
|
||||
/// </summary>
|
||||
public interface IInScopeOrAsWeakBinding : IAsWeakBinding
|
||||
{
|
||||
/// <summary>
|
||||
/// Specify a factory that creates an IRegistration to use for this binding
|
||||
/// </summary>
|
||||
/// <param name="registrationFactory">Registration factory to use</param>
|
||||
/// <returns>Fluent interface to continue configuration</returns>
|
||||
IAsWeakBinding WithRegistrationFactory(RegistrationFactory registrationFactory);
|
||||
|
||||
/// <summary>
|
||||
/// Modify the scope of the binding to Singleton. One instance of this implementation will be generated for this binding.
|
||||
/// </summary>
|
||||
/// <returns>Fluent interface to continue configuration</returns>
|
||||
IAsWeakBinding InSingletonScope();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Fluent interface on which WithKey, AsWeakBinding, or the scoping extensions can be called
|
||||
/// </summary>
|
||||
public interface IInScopeOrWithKeyOrAsWeakBinding : IInScopeOrAsWeakBinding
|
||||
{
|
||||
/// <summary>
|
||||
/// Associate a key with this binding. Requests for the service will have to specify this key to retrieve the result of this binding
|
||||
/// </summary>
|
||||
/// <param name="key">Key to associate with this binding</param>
|
||||
/// <returns>Fluent interface to continue configuration</returns>
|
||||
IInScopeOrAsWeakBinding WithKey(string key);
|
||||
}
|
||||
}
|
|
@ -3,31 +3,31 @@ using StyletIoC.Internal.Registrations;
|
|||
using System;
|
||||
using StyletIoC.Creation;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace StyletIoC.Internal.Builders
|
||||
{
|
||||
internal class BuilderAbstractFactoryBinding : BuilderBindingBase
|
||||
{
|
||||
private BuilderTypeKey ServiceType { get { return this.ServiceTypes[0]; } }
|
||||
|
||||
public BuilderAbstractFactoryBinding(List<BuilderTypeKey> serviceTypes)
|
||||
: base(serviceTypes)
|
||||
{
|
||||
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()));
|
||||
}
|
||||
// This should be ensured by the fluent interfaces
|
||||
Trace.Assert(serviceTypes.Count == 1);
|
||||
|
||||
if (this.ServiceType.Type.IsGenericTypeDefinition)
|
||||
throw new StyletIoCRegistrationException(String.Format("Unbound generic type {0} can't be used as an abstract factory", this.ServiceType.Type.GetDescription()));
|
||||
}
|
||||
|
||||
public override void Build(Container container)
|
||||
{
|
||||
foreach (var serviceType in this.ServiceTypes)
|
||||
{
|
||||
var factoryType = container.GetFactoryForType(serviceType.Type);
|
||||
var creator = new AbstractFactoryCreator(factoryType);
|
||||
var registration = new TransientRegistration(creator);
|
||||
var factoryType = container.GetFactoryForType(this.ServiceType.Type);
|
||||
var creator = new AbstractFactoryCreator(factoryType);
|
||||
var registration = new TransientRegistration(creator);
|
||||
|
||||
container.AddRegistration(new TypeKey(serviceType.Type.TypeHandle, serviceType.Key), registration);
|
||||
}
|
||||
container.AddRegistration(new TypeKey(this.ServiceType.Type.TypeHandle, this.ServiceType.Key), registration);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,12 +1,13 @@
|
|||
using StyletIoC.Creation;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
|
||||
namespace StyletIoC.Internal.Builders
|
||||
{
|
||||
internal class BuilderBindTo : IBindTo
|
||||
internal class BuilderBindTo : IBindTo, IAndOrToMultipleServices
|
||||
{
|
||||
private readonly Func<IEnumerable<Assembly>, string, IEnumerable<Assembly>> getAssemblies;
|
||||
public List<BuilderTypeKey> ServiceTypes { get; private set; }
|
||||
|
@ -19,9 +20,32 @@ namespace StyletIoC.Internal.Builders
|
|||
this.getAssemblies = getAssemblies;
|
||||
}
|
||||
|
||||
public IWithKeyOrAndOrToMultipleServices And<TService>()
|
||||
{
|
||||
return this.And(typeof(TService));
|
||||
}
|
||||
|
||||
public IWithKeyOrAndOrToMultipleServices And(Type serviceType)
|
||||
{
|
||||
this.ServiceTypes.Add(new BuilderTypeKey(serviceType));
|
||||
return this;
|
||||
}
|
||||
|
||||
public IAndOrToMultipleServices WithKey(string key)
|
||||
{
|
||||
// Should have been ensured by the fluent interface
|
||||
Trace.Assert(this.ServiceTypes.Count > 0);
|
||||
|
||||
this.ServiceTypes[this.ServiceTypes.Count - 1].Key = key;
|
||||
return this;
|
||||
}
|
||||
|
||||
public IInScopeOrWithKeyOrAsWeakBinding ToSelf()
|
||||
{
|
||||
return this.To(this.ServiceTypes);
|
||||
// This should be ensured by the fluent interfaces
|
||||
Trace.Assert(this.ServiceTypes.Count == 1);
|
||||
|
||||
return this.To(this.ServiceTypes[0].Type);
|
||||
}
|
||||
|
||||
public IInScopeOrWithKeyOrAsWeakBinding To(Type implementationType)
|
||||
|
|
|
@ -4,6 +4,7 @@ using StyletIoC.Internal.Registrations;
|
|||
using System;
|
||||
using System.Reflection;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace StyletIoC.Internal.Builders
|
||||
{
|
||||
|
@ -40,7 +41,10 @@ namespace StyletIoC.Internal.Builders
|
|||
|
||||
public IInScopeOrAsWeakBinding WithKey(string key)
|
||||
{
|
||||
this.ServiceTypes[this.ServiceTypes.Count - 1].Key = key;
|
||||
foreach (var serviceType in this.ServiceTypes)
|
||||
{
|
||||
serviceType.Key = key;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
|
@ -81,9 +85,24 @@ namespace StyletIoC.Internal.Builders
|
|||
|
||||
protected void BindImplementationToServices(Container container, Type implementationType)
|
||||
{
|
||||
foreach (var serviceType in this.ServiceTypes)
|
||||
if (this.ServiceTypes.Count > 1)
|
||||
{
|
||||
this.BindImplementationToSpecificService(container, implementationType, serviceType.Type, serviceType.Key);
|
||||
var firstGenericType = this.ServiceTypes.FirstOrDefault(x => x.Type.IsGenericTypeDefinition);
|
||||
|
||||
if (firstGenericType != null)
|
||||
throw new StyletIoCRegistrationException(String.Format("Cannot create a multiple-service binding with an unbound generic type {0}", firstGenericType.Type.GetDescription()));
|
||||
|
||||
var creator = new TypeCreator(implementationType, container);
|
||||
var registration = this.CreateRegistration(container, creator);
|
||||
|
||||
foreach (var serviceType in this.ServiceTypes)
|
||||
{
|
||||
container.AddRegistration(new TypeKey(serviceType.Type.TypeHandle, serviceType.Key ?? creator.AttributeKey), registration);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
this.BindImplementationToSpecificService(container, implementationType, this.ServiceTypes[0].Type, this.ServiceTypes[0].Key);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -10,17 +10,21 @@ namespace StyletIoC.Internal.Builders
|
|||
internal class BuilderToAllImplementationsBinding : BuilderBindingBase
|
||||
{
|
||||
private readonly IEnumerable<Assembly> assemblies;
|
||||
private BuilderTypeKey ServiceType { get { return this.ServiceTypes[0]; } }
|
||||
|
||||
public BuilderToAllImplementationsBinding(List<BuilderTypeKey> serviceTypes, IEnumerable<Assembly> assemblies)
|
||||
: base(serviceTypes)
|
||||
{
|
||||
// This should be ensured by the fluent interfaces
|
||||
Trace.Assert(this.ServiceTypes.Count == 1);
|
||||
|
||||
this.assemblies = assemblies;
|
||||
}
|
||||
|
||||
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.ServiceTypes || (x.IsGenericType && x.GetGenericTypeDefinition() == this.ServiceTypes))
|
||||
let baseType = type.GetBaseTypesAndInterfaces().FirstOrDefault(x => x == this.ServiceType.Type || (x.IsGenericType && x.GetGenericTypeDefinition() == this.ServiceType.Type))
|
||||
where baseType != null
|
||||
select new { Type = type, Base = baseType.ContainsGenericParameters ? baseType.GetGenericTypeDefinition() : baseType };
|
||||
|
||||
|
@ -28,8 +32,8 @@ namespace StyletIoC.Internal.Builders
|
|||
{
|
||||
try
|
||||
{
|
||||
this.EnsureType(candidate.Type, candidate.Base);
|
||||
this.BindImplementationToService(container, candidate.Type, candidate.Base);
|
||||
EnsureType(candidate.Type, candidate.Base);
|
||||
this.BindImplementationToSpecificService(container, candidate.Type, candidate.Base, this.ServiceType.Key);
|
||||
}
|
||||
catch (StyletIoCRegistrationException e)
|
||||
{
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
using StyletIoC.Creation;
|
||||
using StyletIoC.Internal.Creators;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace StyletIoC.Internal
|
||||
{
|
||||
|
@ -21,7 +22,8 @@ namespace StyletIoC.Internal
|
|||
|
||||
public IRegistration CreateRegistrationForTypeAndKey(Type boundType, string boundKey)
|
||||
{
|
||||
return this.RegistrationFactory(this.parentContext, this.serviceType, new TypeCreator(boundType, this.parentContext), boundKey);
|
||||
var serviceTypes = new List<BuilderTypeKey>() { new BuilderTypeKey(this.serviceType, boundKey) };
|
||||
return this.RegistrationFactory(this.parentContext, serviceTypes, new TypeCreator(boundType, this.parentContext));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,139 +8,6 @@ using System.Reflection;
|
|||
|
||||
namespace StyletIoC
|
||||
{
|
||||
/// <summary>
|
||||
/// Interface for selecting what to bind a service to.
|
||||
/// Call StyletIoCBuilder.Bind(..) to get an instance of this
|
||||
/// </summary>
|
||||
public interface IBindTo
|
||||
{
|
||||
/// <summary>
|
||||
/// Bind the specified service to itself - if you self-bind MyClass, and request an instance of MyClass, you'll get an instance of MyClass.
|
||||
/// </summary>
|
||||
/// <returns>Fluent interface to continue configuration</returns>
|
||||
IInScopeOrWithKeyOrAsWeakBinding ToSelf();
|
||||
|
||||
/// <summary>
|
||||
/// Bind the specified service to another type which implements that service. E.g. builder.Bind{IMyClass}().To(typeof(MyClass)), and request an IMyClass: you'll get a MyClass.
|
||||
/// </summary>
|
||||
/// <param name="implementationType">Type to bind the service to</param>
|
||||
/// <returns>Fluent interface to continue configuration</returns>
|
||||
IInScopeOrWithKeyOrAsWeakBinding To(Type implementationType);
|
||||
|
||||
/// <summary>
|
||||
/// Bind the specified service to another type which implements that service. E.g. builder.Bind{IMyClass}().To{MyClass}(), and request an IMyClass: you'll get a MyClass.
|
||||
/// </summary>
|
||||
/// <typeparam name="TImplementation">Type to bind the service to</typeparam>
|
||||
/// <returns>Fluent interface to continue configuration</returns>
|
||||
IInScopeOrWithKeyOrAsWeakBinding To<TImplementation>();
|
||||
|
||||
/// <summary>
|
||||
/// Bind the specified service to a factory delegate, which will be called when an instance is required. E.g. ...ToFactory(c => new MyClass(c.Get{Dependency}(), "foo"))
|
||||
/// </summary>
|
||||
/// <typeparam name="TImplementation">Type returned by the factory delegate. Must implement the service</typeparam>
|
||||
/// <param name="factory">Factory delegate to bind got</param>
|
||||
/// <returns>Fluent interface to continue configuration</returns>
|
||||
IInScopeOrWithKeyOrAsWeakBinding ToFactory<TImplementation>(Func<IRegistrationContext, TImplementation> factory);
|
||||
|
||||
/// <summary>
|
||||
/// Bind the specified service to the given untyped instance
|
||||
/// </summary>
|
||||
/// <param name="instance">Instance to use</param>
|
||||
/// <returns>Fluent interface to continue configuration</returns>
|
||||
IWithKeyOrAsWeakBinding ToInstance(object instance);
|
||||
|
||||
/// <summary>
|
||||
/// If the service is an interface with a number of methods which return other types, generate an implementation of that abstract factory and bind it to the interface.
|
||||
/// </summary>
|
||||
/// <returns>Fluent interface to continue configuration</returns>
|
||||
IWithKeyOrAsWeakBinding ToAbstractFactory();
|
||||
|
||||
/// <summary>
|
||||
/// Discover all implementations of the service in the specified assemblies / the current assembly, and bind those to the service
|
||||
/// </summary>
|
||||
/// <param name="assemblies">Assemblies to search. If empty / null, searches the current assembly</param>
|
||||
/// <returns>Fluent interface to continue configuration</returns>
|
||||
IInScopeOrWithKeyOrAsWeakBinding ToAllImplementations(IEnumerable<Assembly> assemblies);
|
||||
|
||||
/// <summary>
|
||||
/// Discover all implementations of the service in the specified assemblies / the current assembly, and bind those to the service
|
||||
/// </summary>
|
||||
/// <param name="assemblies">Assemblies to search. If empty / null, searches the current assembly</param>
|
||||
/// <returns>Fluent interface to continue configuration</returns>
|
||||
IInScopeOrWithKeyOrAsWeakBinding ToAllImplementations(params Assembly[] assemblies);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Fluent interface on which AsWeakBinding can be called
|
||||
/// </summary>
|
||||
public interface IAsWeakBinding
|
||||
{
|
||||
/// <summary>
|
||||
/// Mark the binding as weak
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// When the container is built, each collection of registrations for each Type+key combination is examined.
|
||||
/// If only weak bindings exist, then all bindings are built into the container.
|
||||
/// If any normal bindings exist, then all weak bindings are ignored, and only the normal bindings are built into the container.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// This is very useful for integration StyletIoC into a framework. The framework can add default bindings for services as
|
||||
/// weak bindings, and the user can use normal bindings. If the user does specify a binding, then this will override
|
||||
/// the binding set by the framework.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// This is also used by AutoBind when self-binding concrete types, for the sme reason.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
void AsWeakBinding();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Fluent interface on which WithKey or AsWeakBinding can be called
|
||||
/// </summary>
|
||||
public interface IWithKeyOrAsWeakBinding : IAsWeakBinding
|
||||
{
|
||||
/// <summary>
|
||||
/// Associate a key with this binding. Requests for the service will have to specify this key to retrieve the result of this binding
|
||||
/// </summary>
|
||||
/// <param name="key">Key to associate with this binding</param>
|
||||
/// <returns>Fluent interface to continue configuration</returns>
|
||||
IAsWeakBinding WithKey(string key);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Fluent interface on which methods to modify the scope can be called
|
||||
/// </summary>
|
||||
public interface IInScopeOrAsWeakBinding : IAsWeakBinding
|
||||
{
|
||||
/// <summary>
|
||||
/// Specify a factory that creates an IRegistration to use for this binding
|
||||
/// </summary>
|
||||
/// <param name="registrationFactory">Registration factory to use</param>
|
||||
/// <returns>Fluent interface to continue configuration</returns>
|
||||
IAsWeakBinding WithRegistrationFactory(RegistrationFactory registrationFactory);
|
||||
|
||||
/// <summary>
|
||||
/// Modify the scope of the binding to Singleton. One instance of this implementation will be generated for this binding.
|
||||
/// </summary>
|
||||
/// <returns>Fluent interface to continue configuration</returns>
|
||||
IAsWeakBinding InSingletonScope();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Fluent interface on which WithKey, AsWeakBinding, or the scoping extensions can be called
|
||||
/// </summary>
|
||||
public interface IInScopeOrWithKeyOrAsWeakBinding : IInScopeOrAsWeakBinding
|
||||
{
|
||||
/// <summary>
|
||||
/// Associate a key with this binding. Requests for the service will have to specify this key to retrieve the result of this binding
|
||||
/// </summary>
|
||||
/// <param name="key">Key to associate with this binding</param>
|
||||
/// <returns>Fluent interface to continue configuration</returns>
|
||||
IInScopeOrAsWeakBinding WithKey(string key);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This IStyletIoCBuilder is the only way to create an IContainer. Binding are registered using the builder, than an IContainer generated.
|
||||
/// </summary>
|
||||
|
@ -300,9 +167,17 @@ namespace StyletIoC
|
|||
// Just in case they want it
|
||||
this.Bind<IContainer>().ToInstance(container).AsWeakBinding();
|
||||
|
||||
// For each TypeKey, we remove any weak bindings if there are any strong bindings
|
||||
var groups = this.bindings.GroupBy(x => new { Key = x.Key, Type = x.ServiceType });
|
||||
var filtered = groups.SelectMany(group => group.Any(x => !x.IsWeak) ? group.Where(x => !x.IsWeak) : group);
|
||||
// For each binding which is weak, if another binding exists with any of the same type+key which is strong, we remove this binding
|
||||
var groups = (from binding in this.bindings
|
||||
from serviceType in binding.ServiceTypes
|
||||
select new { ServiceType = serviceType, Binding = binding })
|
||||
.ToLookup(x => x.ServiceType);
|
||||
|
||||
var filtered = from binding in this.bindings
|
||||
where !binding.IsWeak ||
|
||||
binding.ServiceTypes.Any(serviceType => groups.Contains(serviceType) && groups[serviceType].Any(groupItem => groupItem.Binding.IsWeak))
|
||||
select binding;
|
||||
|
||||
foreach (var binding in filtered)
|
||||
{
|
||||
binding.Build(container);
|
||||
|
|
|
@ -0,0 +1,90 @@
|
|||
using NUnit.Framework;
|
||||
using StyletIoC;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace StyletUnitTests
|
||||
{
|
||||
[TestFixture]
|
||||
public class StyletIoCMultipleBindingTests
|
||||
{
|
||||
|
||||
private interface I1 { }
|
||||
|
||||
private class C1 : I1 { }
|
||||
|
||||
private interface I2<T> { }
|
||||
private class C2<T> : I2<T> { }
|
||||
|
||||
[Test]
|
||||
public void SingletonMultipleTypeBindingIsSingleton()
|
||||
{
|
||||
var builder = new StyletIoCBuilder();
|
||||
builder.Bind<I1>().And<C1>().To<C1>().InSingletonScope();
|
||||
var ioc = builder.BuildContainer();
|
||||
|
||||
Assert.AreEqual(ioc.Get<C1>(), ioc.Get<I1>());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void SingletonMultipleFactoryBindingIsSingleton()
|
||||
{
|
||||
var builder = new StyletIoCBuilder();
|
||||
builder.Bind<I1>().And<C1>().ToFactory(x => new C1()).InSingletonScope();
|
||||
var ioc = builder.BuildContainer();
|
||||
|
||||
Assert.AreEqual(ioc.Get<C1>(), ioc.Get<I1>());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void SingletonMultipleInstanceBindingWorks()
|
||||
{
|
||||
var builder = new StyletIoCBuilder();
|
||||
builder.Bind<I1>().And<C1>().ToInstance(new C1());
|
||||
var ioc = builder.BuildContainer();
|
||||
|
||||
Assert.AreEqual(ioc.Get<C1>(), ioc.Get<I1>());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void RejectsMultipleUnboundGenericBindings()
|
||||
{
|
||||
var builder = new StyletIoCBuilder();
|
||||
builder.Bind(typeof(I2<>)).And(typeof(C2<>)).To(typeof(C2<>)).InSingletonScope();
|
||||
Assert.Throws<StyletIoCRegistrationException>(() => builder.BuildContainer());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void RejectsMultipleBindingsForTheSameType()
|
||||
{
|
||||
var builder = new StyletIoCBuilder();
|
||||
builder.Bind<I1>().And<I1>().To<C1>();
|
||||
Assert.Throws<StyletIoCRegistrationException>(() => builder.BuildContainer());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void AllowsMultipleBindingsWithDifferentKeys()
|
||||
{
|
||||
var builder = new StyletIoCBuilder();
|
||||
builder.Bind<I1>().WithKey("foo").And<I1>().To<C1>().InSingletonScope();
|
||||
var ioc = builder.BuildContainer();
|
||||
|
||||
Assert.AreEqual(ioc.Get<I1>(), ioc.Get<I1>("foo"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void FinalWithKeyAppliesToAllBindings()
|
||||
{
|
||||
var builder = new StyletIoCBuilder();
|
||||
builder.Bind<I1>().And<C1>().To<C1>().WithKey("foo").InSingletonScope();
|
||||
var ioc = builder.BuildContainer();
|
||||
|
||||
Assert.DoesNotThrow(() => ioc.Get<I1>("foo"));
|
||||
Assert.DoesNotThrow(() => ioc.Get<C1>("foo"));
|
||||
Assert.AreEqual(ioc.Get<I1>("foo"), ioc.Get<C1>("foo"));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -87,6 +87,7 @@
|
|||
<Compile Include="StyletIoC\StyletIoCFuncFactoryTests.cs" />
|
||||
<Compile Include="StyletIoC\StyletIoCInstanceBindingTests.cs" />
|
||||
<Compile Include="StyletIoC\StyletIoCModuleTests.cs" />
|
||||
<Compile Include="StyletIoC\StyletIoCMultipleBindingTests.cs" />
|
||||
<Compile Include="TraceLoggerTests.cs" />
|
||||
<Compile Include="EqualityConverterTests.cs" />
|
||||
<Compile Include="EventActionTests.cs" />
|
||||
|
|
Loading…
Reference in New Issue