Start getting towards something that works...

This commit is contained in:
Antony Male 2015-09-28 12:49:47 +01:00
parent 498597c0a6
commit bd18b94e82
11 changed files with 371 additions and 158 deletions

View File

@ -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" />

View File

@ -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;
}
}
}

View File

@ -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);
}
}

View File

@ -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);
}
}
}

View File

@ -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)

View File

@ -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);
}
}

View File

@ -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)
{

View File

@ -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));
}
}
}

View File

@ -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);

View File

@ -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"));
}
}
}

View File

@ -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" />