mirror of https://github.com/AMT-Cheif/Stylet.git
Shake up how autobinding is done in StyletIoC
Instead of creating tons of registrations for all discovered types, instead create those registrations as and when they are requested. This means we don't flood the CLR's type cache with RuntimeTypes which are never used but can never be collected.
This commit is contained in:
parent
a5f642d95c
commit
9b1b1308b6
|
@ -1,4 +1,5 @@
|
|||
using StyletIoC.Creation;
|
||||
using StyletIoC.Internal.Creators;
|
||||
using StyletIoC.Internal.RegistrationCollections;
|
||||
using StyletIoC.Internal.Registrations;
|
||||
using System;
|
||||
|
@ -18,6 +19,8 @@ namespace StyletIoC.Internal
|
|||
// ReSharper disable once RedundantExtendsListEntry
|
||||
internal class Container : IContainer, IRegistrationContext
|
||||
{
|
||||
private readonly List<Assembly> autobindAssemblies;
|
||||
|
||||
/// <summary>
|
||||
/// Maps a [type, key] pair to a collection of registrations for that keypair. You can retrieve an instance of the type from the registration
|
||||
/// </summary>
|
||||
|
@ -53,6 +56,11 @@ namespace StyletIoC.Internal
|
|||
|
||||
private bool disposed;
|
||||
|
||||
public Container(List<Assembly> autobindAssemblies)
|
||||
{
|
||||
this.autobindAssemblies = autobindAssemblies ?? new List<Assembly>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Compile all known bindings (which would otherwise be compiled when needed), checking the dependency graph for consistency
|
||||
/// </summary>
|
||||
|
@ -161,7 +169,8 @@ namespace StyletIoC.Internal
|
|||
|
||||
if (this.registrations.TryGetValue(typeKey, out registrations) ||
|
||||
this.TryCreateFuncFactory(typeKey, out registrations) ||
|
||||
this.TryCreateGenericTypesForUnboundGeneric(typeKey, out registrations))
|
||||
this.TryCreateGenericTypesForUnboundGeneric(typeKey, out registrations) ||
|
||||
this.TryCreateSelfBinding(typeKey, out registrations))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
@ -222,6 +231,27 @@ namespace StyletIoC.Internal
|
|||
return this.TryRetrieveGetAllRegistrationFromElementType(new TypeKey(elementType, typeKey.Key), typeKey.Type, out registration);
|
||||
}
|
||||
|
||||
private bool TryCreateSelfBinding(TypeKey typeKey, out IRegistrationCollection registrations)
|
||||
{
|
||||
registrations = null;
|
||||
|
||||
if (typeKey.Type.IsAbstract || !typeKey.Type.IsClass)
|
||||
return false;
|
||||
|
||||
var injectAttribute = typeKey.Type.GetCustomAttribute<InjectAttribute>(true);
|
||||
if (injectAttribute != null && injectAttribute.Key != typeKey.Key)
|
||||
return false;
|
||||
|
||||
// Only allow types in our whitelisted assemblies
|
||||
// This stops us trying to charge off and create List<T> or some other BCL class which we don't have a hope in hell of creating
|
||||
// This in turn leads to some very hard-to-debug error cases where we descend into infinite recursion on some random type
|
||||
if (!this.autobindAssemblies.Contains(typeKey.Type.Assembly))
|
||||
return false;
|
||||
|
||||
registrations = this.AddRegistration(typeKey, new TransientRegistration(new TypeCreator(typeKey.Type, this)));
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// If the given type is a Func{T} or a Func{string, T}, get a registration which can create an instance of it
|
||||
/// </summary>
|
||||
|
@ -325,7 +355,8 @@ namespace StyletIoC.Internal
|
|||
// Try to get registrations. If there are none, see if we can add some from unbound generics
|
||||
if (this.registrations.TryGetValue(typeKey, out registrations) ||
|
||||
this.TryCreateFuncFactory(typeKey, out registrations) ||
|
||||
this.TryCreateGenericTypesForUnboundGeneric(typeKey, out registrations))
|
||||
this.TryCreateGenericTypesForUnboundGeneric(typeKey, out registrations) ||
|
||||
this.TryCreateSelfBinding(typeKey, out registrations))
|
||||
{
|
||||
readOnlyRegistrations = registrations;
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@ using System;
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace StyletIoC
|
||||
{
|
||||
|
@ -203,12 +204,13 @@ namespace StyletIoC
|
|||
public class StyletIoCBuilder : IStyletIoCBuilder
|
||||
{
|
||||
private readonly List<BuilderBindTo> bindings = new List<BuilderBindTo>();
|
||||
private List<Assembly> autobindAssemblies;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the list of assemblies searched by Autobind and ToAllImplementatinos
|
||||
/// </summary>
|
||||
public List<Assembly> Assemblies { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Initialises a new instance of the <see cref="StyletIoCBuilder"/> class
|
||||
/// </summary>
|
||||
|
@ -254,14 +256,9 @@ namespace StyletIoC
|
|||
/// <param name="assemblies">Assemblies to search, in addition to the Assemblies property</param>
|
||||
public void Autobind(IEnumerable<Assembly> assemblies)
|
||||
{
|
||||
// We self-bind concrete classes only
|
||||
var classes = this.GetAssemblies(assemblies, "Autobind").SelectMany(x => x.GetTypes()).Where(c => c.IsClass && !c.IsAbstract);
|
||||
foreach (var cls in classes)
|
||||
{
|
||||
// It's not actually possible for this to fail with a StyletIoCRegistrationException (at least currently)
|
||||
// It's a self-binding, and those are always safe (at this stage - it could fall over when the containing's actually build)
|
||||
this.Bind(cls).To(cls).AsWeakBinding();
|
||||
}
|
||||
// If they've called Autobind before, then add the new set of assemblies on
|
||||
var existing = this.autobindAssemblies ?? Enumerable.Empty<Assembly>();
|
||||
this.autobindAssemblies = existing.Concat(this.GetAssemblies(assemblies, "Autobind")).Distinct().ToList();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -300,7 +297,7 @@ namespace StyletIoC
|
|||
/// <returns>An IContainer, which should be used from now on</returns>
|
||||
public IContainer BuildContainer()
|
||||
{
|
||||
var container = new Container();
|
||||
var container = new Container(this.autobindAssemblies);
|
||||
|
||||
// Just in case they want it
|
||||
this.Bind<IContainer>().ToInstance(container).AsWeakBinding();
|
||||
|
|
Loading…
Reference in New Issue