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\ILogger.cs" />
|
||||||
<Compile Include="Logging\NullLogger.cs" />
|
<Compile Include="Logging\NullLogger.cs" />
|
||||||
<Compile Include="Logging\TraceLogger.cs" />
|
<Compile Include="Logging\TraceLogger.cs" />
|
||||||
|
<Compile Include="StyletIoC\Creation\BuilderTypeKey.cs" />
|
||||||
<Compile Include="StyletIoC\Creation\ICreator.cs" />
|
<Compile Include="StyletIoC\Creation\ICreator.cs" />
|
||||||
<Compile Include="StyletIoC\Creation\IRegistration.cs" />
|
<Compile Include="StyletIoC\Creation\IRegistration.cs" />
|
||||||
|
<Compile Include="StyletIoC\FluentInterface.cs" />
|
||||||
<Compile Include="StyletIoC\Internal\Builders\BuilderAbstractFactoryBinding.cs" />
|
<Compile Include="StyletIoC\Internal\Builders\BuilderAbstractFactoryBinding.cs" />
|
||||||
<Compile Include="StyletIoC\Internal\Builders\BuilderBindingBase.cs" />
|
<Compile Include="StyletIoC\Internal\Builders\BuilderBindingBase.cs" />
|
||||||
<Compile Include="StyletIoC\Internal\Builders\BuilderBindTo.cs" />
|
<Compile Include="StyletIoC\Internal\Builders\BuilderBindTo.cs" />
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
namespace StyletIoC.Creation
|
namespace StyletIoC.Creation
|
||||||
{
|
{
|
||||||
public class BuilderTypeKey
|
public class BuilderTypeKey : IEquatable<BuilderTypeKey>
|
||||||
{
|
{
|
||||||
public Type Type { get; set; }
|
public Type Type { get; set; }
|
||||||
public string Key { get; set; }
|
public string Key { get; set; }
|
||||||
|
@ -11,5 +11,35 @@ namespace StyletIoC.Creation
|
||||||
{
|
{
|
||||||
this.Type = type;
|
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 System;
|
||||||
using StyletIoC.Creation;
|
using StyletIoC.Creation;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics;
|
||||||
|
|
||||||
namespace StyletIoC.Internal.Builders
|
namespace StyletIoC.Internal.Builders
|
||||||
{
|
{
|
||||||
internal class BuilderAbstractFactoryBinding : BuilderBindingBase
|
internal class BuilderAbstractFactoryBinding : BuilderBindingBase
|
||||||
{
|
{
|
||||||
|
private BuilderTypeKey ServiceType { get { return this.ServiceTypes[0]; } }
|
||||||
|
|
||||||
public BuilderAbstractFactoryBinding(List<BuilderTypeKey> serviceTypes)
|
public BuilderAbstractFactoryBinding(List<BuilderTypeKey> serviceTypes)
|
||||||
: base(serviceTypes)
|
: base(serviceTypes)
|
||||||
{
|
{
|
||||||
foreach (var serviceType in this.ServiceTypes)
|
// This should be ensured by the fluent interfaces
|
||||||
{
|
Trace.Assert(serviceTypes.Count == 1);
|
||||||
if (serviceType.Type.IsGenericTypeDefinition)
|
|
||||||
throw new StyletIoCRegistrationException(String.Format("Unbound generic type {0} can't be used as an abstract factory", serviceType.Type.GetDescription()));
|
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)
|
public override void Build(Container container)
|
||||||
{
|
{
|
||||||
foreach (var serviceType in this.ServiceTypes)
|
var factoryType = container.GetFactoryForType(this.ServiceType.Type);
|
||||||
{
|
var creator = new AbstractFactoryCreator(factoryType);
|
||||||
var factoryType = container.GetFactoryForType(serviceType.Type);
|
var registration = new TransientRegistration(creator);
|
||||||
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 StyletIoC.Creation;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
|
|
||||||
namespace StyletIoC.Internal.Builders
|
namespace StyletIoC.Internal.Builders
|
||||||
{
|
{
|
||||||
internal class BuilderBindTo : IBindTo
|
internal class BuilderBindTo : IBindTo, IAndOrToMultipleServices
|
||||||
{
|
{
|
||||||
private readonly Func<IEnumerable<Assembly>, string, IEnumerable<Assembly>> getAssemblies;
|
private readonly Func<IEnumerable<Assembly>, string, IEnumerable<Assembly>> getAssemblies;
|
||||||
public List<BuilderTypeKey> ServiceTypes { get; private set; }
|
public List<BuilderTypeKey> ServiceTypes { get; private set; }
|
||||||
|
@ -19,9 +20,32 @@ namespace StyletIoC.Internal.Builders
|
||||||
this.getAssemblies = getAssemblies;
|
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()
|
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)
|
public IInScopeOrWithKeyOrAsWeakBinding To(Type implementationType)
|
||||||
|
|
|
@ -4,6 +4,7 @@ using StyletIoC.Internal.Registrations;
|
||||||
using System;
|
using System;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
namespace StyletIoC.Internal.Builders
|
namespace StyletIoC.Internal.Builders
|
||||||
{
|
{
|
||||||
|
@ -40,7 +41,10 @@ namespace StyletIoC.Internal.Builders
|
||||||
|
|
||||||
public IInScopeOrAsWeakBinding WithKey(string key)
|
public IInScopeOrAsWeakBinding WithKey(string key)
|
||||||
{
|
{
|
||||||
this.ServiceTypes[this.ServiceTypes.Count - 1].Key = key;
|
foreach (var serviceType in this.ServiceTypes)
|
||||||
|
{
|
||||||
|
serviceType.Key = key;
|
||||||
|
}
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -81,9 +85,24 @@ namespace StyletIoC.Internal.Builders
|
||||||
|
|
||||||
protected void BindImplementationToServices(Container container, Type implementationType)
|
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
|
internal class BuilderToAllImplementationsBinding : BuilderBindingBase
|
||||||
{
|
{
|
||||||
private readonly IEnumerable<Assembly> assemblies;
|
private readonly IEnumerable<Assembly> assemblies;
|
||||||
|
private BuilderTypeKey ServiceType { get { return this.ServiceTypes[0]; } }
|
||||||
|
|
||||||
public BuilderToAllImplementationsBinding(List<BuilderTypeKey> serviceTypes, IEnumerable<Assembly> assemblies)
|
public BuilderToAllImplementationsBinding(List<BuilderTypeKey> serviceTypes, IEnumerable<Assembly> assemblies)
|
||||||
: base(serviceTypes)
|
: base(serviceTypes)
|
||||||
{
|
{
|
||||||
|
// This should be ensured by the fluent interfaces
|
||||||
|
Trace.Assert(this.ServiceTypes.Count == 1);
|
||||||
|
|
||||||
this.assemblies = assemblies;
|
this.assemblies = assemblies;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Build(Container container)
|
public override void Build(Container container)
|
||||||
{
|
{
|
||||||
var candidates = from type in this.assemblies.Distinct().SelectMany(x => x.GetTypes())
|
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
|
where baseType != null
|
||||||
select new { Type = type, Base = baseType.ContainsGenericParameters ? baseType.GetGenericTypeDefinition() : baseType };
|
select new { Type = type, Base = baseType.ContainsGenericParameters ? baseType.GetGenericTypeDefinition() : baseType };
|
||||||
|
|
||||||
|
@ -28,8 +32,8 @@ namespace StyletIoC.Internal.Builders
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
this.EnsureType(candidate.Type, candidate.Base);
|
EnsureType(candidate.Type, candidate.Base);
|
||||||
this.BindImplementationToService(container, candidate.Type, candidate.Base);
|
this.BindImplementationToSpecificService(container, candidate.Type, candidate.Base, this.ServiceType.Key);
|
||||||
}
|
}
|
||||||
catch (StyletIoCRegistrationException e)
|
catch (StyletIoCRegistrationException e)
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
using StyletIoC.Creation;
|
using StyletIoC.Creation;
|
||||||
using StyletIoC.Internal.Creators;
|
using StyletIoC.Internal.Creators;
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
namespace StyletIoC.Internal
|
namespace StyletIoC.Internal
|
||||||
{
|
{
|
||||||
|
@ -21,7 +22,8 @@ namespace StyletIoC.Internal
|
||||||
|
|
||||||
public IRegistration CreateRegistrationForTypeAndKey(Type boundType, string boundKey)
|
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
|
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>
|
/// <summary>
|
||||||
/// This IStyletIoCBuilder is the only way to create an IContainer. Binding are registered using the builder, than an IContainer generated.
|
/// This IStyletIoCBuilder is the only way to create an IContainer. Binding are registered using the builder, than an IContainer generated.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -300,9 +167,17 @@ namespace StyletIoC
|
||||||
// Just in case they want it
|
// Just in case they want it
|
||||||
this.Bind<IContainer>().ToInstance(container).AsWeakBinding();
|
this.Bind<IContainer>().ToInstance(container).AsWeakBinding();
|
||||||
|
|
||||||
// For each TypeKey, we remove any weak bindings if there are any strong bindings
|
// 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 = this.bindings.GroupBy(x => new { Key = x.Key, Type = x.ServiceType });
|
var groups = (from binding in this.bindings
|
||||||
var filtered = groups.SelectMany(group => group.Any(x => !x.IsWeak) ? group.Where(x => !x.IsWeak) : group);
|
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)
|
foreach (var binding in filtered)
|
||||||
{
|
{
|
||||||
binding.Build(container);
|
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\StyletIoCFuncFactoryTests.cs" />
|
||||||
<Compile Include="StyletIoC\StyletIoCInstanceBindingTests.cs" />
|
<Compile Include="StyletIoC\StyletIoCInstanceBindingTests.cs" />
|
||||||
<Compile Include="StyletIoC\StyletIoCModuleTests.cs" />
|
<Compile Include="StyletIoC\StyletIoCModuleTests.cs" />
|
||||||
|
<Compile Include="StyletIoC\StyletIoCMultipleBindingTests.cs" />
|
||||||
<Compile Include="TraceLoggerTests.cs" />
|
<Compile Include="TraceLoggerTests.cs" />
|
||||||
<Compile Include="EqualityConverterTests.cs" />
|
<Compile Include="EqualityConverterTests.cs" />
|
||||||
<Compile Include="EventActionTests.cs" />
|
<Compile Include="EventActionTests.cs" />
|
||||||
|
|
Loading…
Reference in New Issue