Throw (by default) if ToAllImplementations does not find any implementations

This will happen if someone takes a concrete class (with no subclasses), uses
ToAllImplementations on it (and InSingletonScope), and wonders why the singleton
registration didn't 'take': the ToAllImplementations didn't create any bindings,
so we fell back to auto-binding the type
This commit is contained in:
Antony Male 2016-03-02 17:15:22 +00:00
parent fc869b642a
commit 235504941f
4 changed files with 41 additions and 9 deletions

View File

@ -69,15 +69,17 @@ namespace StyletIoC
/// 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>
/// <param name="allowZeroImplementations">By default, ToAllImplementations will throw an exception if no implementations are found. Set this parameter to true to allow this case</param>
/// <returns>Fluent interface to continue configuration</returns>
IInScopeOrWithKeyOrAsWeakBinding ToAllImplementations(IEnumerable<Assembly> assemblies);
IInScopeOrWithKeyOrAsWeakBinding ToAllImplementations(IEnumerable<Assembly> assemblies, bool allowZeroImplementations = false);
/// <summary>
/// Discover all implementations of the service in the specified assemblies / the current assembly, and bind those to the service
/// </summary>
/// <param name="allowZeroImplementations">By default, ToAllImplementations will throw an exception if no implementations are found. Set this parameter to true to allow this case</param>
/// <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);
IInScopeOrWithKeyOrAsWeakBinding ToAllImplementations(bool allowZeroImplementations = false, params Assembly[] assemblies);
}
/// <summary>

View File

@ -77,15 +77,15 @@ namespace StyletIoC.Internal.Builders
return this.builderBinding;
}
public IInScopeOrWithKeyOrAsWeakBinding ToAllImplementations(IEnumerable<Assembly> assemblies)
public IInScopeOrWithKeyOrAsWeakBinding ToAllImplementations(IEnumerable<Assembly> assemblies, bool allowZeroImplementations = false)
{
this.builderBinding = new BuilderToAllImplementationsBinding(this.ServiceTypes, this.getAssemblies(assemblies, "ToAllImplementations"));
this.builderBinding = new BuilderToAllImplementationsBinding(this.ServiceTypes, this.getAssemblies(assemblies, "ToAllImplementations"), allowZeroImplementations);
return this.builderBinding;
}
public IInScopeOrWithKeyOrAsWeakBinding ToAllImplementations(params Assembly[] assemblies)
public IInScopeOrWithKeyOrAsWeakBinding ToAllImplementations(bool allowZeroImplementations = false, params Assembly[] assemblies)
{
return this.ToAllImplementations(assemblies.AsEnumerable());
return this.ToAllImplementations(assemblies.AsEnumerable(), allowZeroImplementations);
}
internal void Build(Container container)

View File

@ -10,23 +10,31 @@ namespace StyletIoC.Internal.Builders
internal class BuilderToAllImplementationsBinding : BuilderBindingBase
{
private readonly IEnumerable<Assembly> assemblies;
private readonly bool allowZeroImplementations;
private BuilderTypeKey ServiceType { get { return this.ServiceTypes[0]; } }
public BuilderToAllImplementationsBinding(List<BuilderTypeKey> serviceTypes, IEnumerable<Assembly> assemblies)
public BuilderToAllImplementationsBinding(List<BuilderTypeKey> serviceTypes, IEnumerable<Assembly> assemblies, bool allowZeroImplementations)
: base(serviceTypes)
{
// This should be ensured by the fluent interfaces
Trace.Assert(this.ServiceTypes.Count == 1);
this.assemblies = assemblies;
this.allowZeroImplementations = allowZeroImplementations;
}
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.ServiceType.Type || (x.IsGenericType && x.GetGenericTypeDefinition() == this.ServiceType.Type))
where baseType != null
select new { Type = type, Base = baseType.ContainsGenericParameters ? baseType.GetGenericTypeDefinition() : baseType };
select new { Type = type, Base = baseType.ContainsGenericParameters ? baseType.GetGenericTypeDefinition() : baseType }).ToList();
if (!this.allowZeroImplementations && candidates.Count == 0)
{
throw new StyletIoCRegistrationException(String.Format("Did not find any implementations of the type {0}", this.ServiceType.Type));
}
foreach (var candidate in candidates)
{

View File

@ -26,6 +26,9 @@ namespace StyletUnitTests
[Inject("Key")]
class C4 { }
interface I5 { }
class C5 { }
[Test]
public void NongenericInterfaceToAllImplementations()
{
@ -162,5 +165,24 @@ namespace StyletUnitTests
Assert.IsInstanceOf<C11>(ioc.Get<C11>());
}
[Test]
public void ToAllImplementationsThrowsIfNoImplementationsFound()
{
var builder = new StyletIoCBuilder();
builder.Bind<I5>().ToAllImplementations();
Assert.Throws<StyletIoCRegistrationException>(() => builder.BuildContainer());
}
[Test]
public void ToAllImplementationsDoesNotThrowIfNoImplementationsFoundAndAllowZeroImplementationsIsTrue()
{
var builder = new StyletIoCBuilder();
builder.Bind<I5>().ToAllImplementations(allowZeroImplementations: true);
IContainer ioc = null;
Assert.DoesNotThrow(() => ioc = builder.BuildContainer());
Assert.DoesNotThrow(() => ioc.GetAll<I5>());
}
}
}