2019-12-08 21:23:54 +01:00
using System ;
using System.Collections.Generic ;
using System.Linq ;
using System.Reflection ;
namespace Swan.DependencyInjection {
/// <summary>
/// The concrete implementation of a simple IoC container
/// based largely on TinyIoC (https://github.com/grumpydev/TinyIoC).
/// </summary>
/// <seealso cref="System.IDisposable" />
public partial class DependencyContainer : IDisposable {
private readonly Object _autoRegisterLock = new Object ( ) ;
private Boolean _disposed ;
static DependencyContainer ( ) {
}
/// <summary>
/// Initializes a new instance of the <see cref="DependencyContainer"/> class.
/// </summary>
public DependencyContainer ( ) {
this . RegisteredTypes = new TypesConcurrentDictionary ( this ) ;
_ = this . Register ( this ) ;
}
private DependencyContainer ( DependencyContainer parent ) : this ( ) = > this . Parent = parent ;
/// <summary>
/// Lazy created Singleton instance of the container for simple scenarios.
/// </summary>
public static DependencyContainer Current { get ; } = new DependencyContainer ( ) ;
internal DependencyContainer Parent {
get ;
}
internal TypesConcurrentDictionary RegisteredTypes {
get ;
}
/// <inheritdoc />
public void Dispose ( ) {
if ( this . _disposed ) {
return ;
}
this . _disposed = true ;
foreach ( IDisposable disposable in this . RegisteredTypes . Values . Select ( item = > item as IDisposable ) ) {
disposable ? . Dispose ( ) ;
}
GC . SuppressFinalize ( this ) ;
}
/// <summary>
/// Gets the child container.
/// </summary>
/// <returns>A new instance of the <see cref="DependencyContainer"/> class.</returns>
public DependencyContainer GetChildContainer ( ) = > new DependencyContainer ( this ) ;
#region Registration
/// <summary>
/// Attempt to automatically register all non-generic classes and interfaces in the current app domain.
/// Types will only be registered if they pass the supplied registration predicate.
/// </summary>
/// <param name="duplicateAction">What action to take when encountering duplicate implementations of an interface/base class.</param>
/// <param name="registrationPredicate">Predicate to determine if a particular type should be registered.</param>
public void AutoRegister ( DependencyContainerDuplicateImplementationAction duplicateAction = DependencyContainerDuplicateImplementationAction . RegisterSingle , Func < Type , Boolean > registrationPredicate = null ) = > this . AutoRegister ( AppDomain . CurrentDomain . GetAssemblies ( ) . Where ( a = > ! IsIgnoredAssembly ( a ) ) , duplicateAction , registrationPredicate ) ;
/// <summary>
/// Attempt to automatically register all non-generic classes and interfaces in the specified assemblies
/// Types will only be registered if they pass the supplied registration predicate.
/// </summary>
/// <param name="assemblies">Assemblies to process.</param>
/// <param name="duplicateAction">What action to take when encountering duplicate implementations of an interface/base class.</param>
/// <param name="registrationPredicate">Predicate to determine if a particular type should be registered.</param>
public void AutoRegister ( IEnumerable < Assembly > assemblies , DependencyContainerDuplicateImplementationAction duplicateAction = DependencyContainerDuplicateImplementationAction . RegisterSingle , Func < Type , Boolean > registrationPredicate = null ) {
lock ( this . _autoRegisterLock ) {
List < Type > types = assemblies . SelectMany ( a = > a . GetAllTypes ( ) ) . Where ( t = > ! IsIgnoredType ( t , registrationPredicate ) ) . ToList ( ) ;
List < Type > concreteTypes = types . Where ( type = > type . IsClass & & ! type . IsAbstract & & type ! = this . GetType ( ) & & type . DeclaringType ! = this . GetType ( ) & & ! type . IsGenericTypeDefinition ) . ToList ( ) ;
foreach ( Type type in concreteTypes ) {
try {
_ = this . RegisteredTypes . Register ( type , String . Empty , GetDefaultObjectFactory ( type , type ) ) ;
} catch ( MethodAccessException ) {
// Ignore methods we can't access - added for Silverlight
}
}
IEnumerable < Type > abstractInterfaceTypes = types . Where ( type = > ( type . IsInterface | | type . IsAbstract ) & & type . DeclaringType ! = this . GetType ( ) & & ! type . IsGenericTypeDefinition ) ;
foreach ( Type type in abstractInterfaceTypes ) {
Type localType = type ;
List < Type > implementations = concreteTypes . Where ( implementationType = > localType . IsAssignableFrom ( implementationType ) ) . ToList ( ) ;
if ( implementations . Skip ( 1 ) . Any ( ) ) {
if ( duplicateAction = = DependencyContainerDuplicateImplementationAction . Fail ) {
throw new DependencyContainerRegistrationException ( type , implementations ) ;
}
if ( duplicateAction = = DependencyContainerDuplicateImplementationAction . RegisterMultiple ) {
_ = this . RegisterMultiple ( type , implementations ) ;
}
}
Type firstImplementation = implementations . FirstOrDefault ( ) ;
if ( firstImplementation = = null ) {
continue ;
}
try {
_ = this . RegisteredTypes . Register ( type , String . Empty , GetDefaultObjectFactory ( type , firstImplementation ) ) ;
} catch ( MethodAccessException ) {
// Ignore methods we can't access - added for Silverlight
}
}
}
}
/// <summary>
/// Creates/replaces a named container class registration with default options.
/// </summary>
/// <param name="registerType">Type to register.</param>
/// <param name="name">Name of registration.</param>
/// <returns>RegisterOptions for fluent API.</returns>
public RegisterOptions Register ( Type registerType , String name = "" ) = > this . RegisteredTypes . Register ( registerType , name , GetDefaultObjectFactory ( registerType , registerType ) ) ;
/// <summary>
/// Creates/replaces a named container class registration with a given implementation and default options.
/// </summary>
/// <param name="registerType">Type to register.</param>
/// <param name="registerImplementation">Type to instantiate that implements RegisterType.</param>
/// <param name="name">Name of registration.</param>
/// <returns>RegisterOptions for fluent API.</returns>
public RegisterOptions Register ( Type registerType , Type registerImplementation , String name = "" ) = > this . RegisteredTypes . Register ( registerType , name , GetDefaultObjectFactory ( registerType , registerImplementation ) ) ;
/// <summary>
/// Creates/replaces a named container class registration with a specific, strong referenced, instance.
/// </summary>
/// <param name="registerType">Type to register.</param>
/// <param name="instance">Instance of RegisterType to register.</param>
/// <param name="name">Name of registration.</param>
/// <returns>RegisterOptions for fluent API.</returns>
public RegisterOptions Register ( Type registerType , Object instance , String name = "" ) = > this . RegisteredTypes . Register ( registerType , name , new InstanceFactory ( registerType , registerType , instance ) ) ;
/// <summary>
/// Creates/replaces a named container class registration with a specific, strong referenced, instance.
/// </summary>
/// <param name="registerType">Type to register.</param>
/// <param name="registerImplementation">Type of instance to register that implements RegisterType.</param>
/// <param name="instance">Instance of RegisterImplementation to register.</param>
/// <param name="name">Name of registration.</param>
/// <returns>RegisterOptions for fluent API.</returns>
public RegisterOptions Register ( Type registerType , Type registerImplementation , Object instance , String name = "" ) = > this . RegisteredTypes . Register ( registerType , name , new InstanceFactory ( registerType , registerImplementation , instance ) ) ;
/// <summary>
/// Creates/replaces a container class registration with a user specified factory.
/// </summary>
/// <param name="registerType">Type to register.</param>
/// <param name="factory">Factory/lambda that returns an instance of RegisterType.</param>
/// <param name="name">Name of registration.</param>
/// <returns>RegisterOptions for fluent API.</returns>
public RegisterOptions Register ( Type registerType , Func < DependencyContainer , Dictionary < String , Object > , Object > factory , String name = "" ) = > this . RegisteredTypes . Register ( registerType , name , new DelegateFactory ( registerType , factory ) ) ;
/// <summary>
/// Creates/replaces a named container class registration with default options.
/// </summary>
/// <typeparam name="TRegister">Type to register.</typeparam>
/// <param name="name">Name of registration.</param>
/// <returns>RegisterOptions for fluent API.</returns>
public RegisterOptions Register < TRegister > ( String name = "" ) where TRegister : class = > this . Register ( typeof ( TRegister ) , name ) ;
/// <summary>
/// Creates/replaces a named container class registration with a given implementation and default options.
/// </summary>
/// <typeparam name="TRegister">Type to register.</typeparam>
/// <typeparam name="TRegisterImplementation">Type to instantiate that implements RegisterType.</typeparam>
/// <param name="name">Name of registration.</param>
/// <returns>RegisterOptions for fluent API.</returns>
public RegisterOptions Register < TRegister , TRegisterImplementation > ( String name = "" ) where TRegister : class where TRegisterImplementation : class , TRegister = > this . Register ( typeof ( TRegister ) , typeof ( TRegisterImplementation ) , name ) ;
/// <summary>
/// Creates/replaces a named container class registration with a specific, strong referenced, instance.
/// </summary>
/// <typeparam name="TRegister">Type to register.</typeparam>
/// <param name="instance">Instance of RegisterType to register.</param>
/// <param name="name">Name of registration.</param>
/// <returns>RegisterOptions for fluent API.</returns>
public RegisterOptions Register < TRegister > ( TRegister instance , String name = "" ) where TRegister : class = > this . Register ( typeof ( TRegister ) , instance , name ) ;
/// <summary>
/// Creates/replaces a named container class registration with a specific, strong referenced, instance.
/// </summary>
/// <typeparam name="TRegister">Type to register.</typeparam>
/// <typeparam name="TRegisterImplementation">Type of instance to register that implements RegisterType.</typeparam>
/// <param name="instance">Instance of RegisterImplementation to register.</param>
/// <param name="name">Name of registration.</param>
/// <returns>RegisterOptions for fluent API.</returns>
public RegisterOptions Register < TRegister , TRegisterImplementation > ( TRegisterImplementation instance , String name = "" ) where TRegister : class where TRegisterImplementation : class , TRegister = > this . Register ( typeof ( TRegister ) , typeof ( TRegisterImplementation ) , instance , name ) ;
/// <summary>
/// Creates/replaces a named container class registration with a user specified factory.
/// </summary>
/// <typeparam name="TRegister">Type to register.</typeparam>
/// <param name="factory">Factory/lambda that returns an instance of RegisterType.</param>
/// <param name="name">Name of registration.</param>
/// <returns>RegisterOptions for fluent API.</returns>
public RegisterOptions Register < TRegister > ( Func < DependencyContainer , Dictionary < String , Object > , TRegister > factory , String name = "" ) where TRegister : class {
if ( factory = = null ) {
throw new ArgumentNullException ( nameof ( factory ) ) ;
}
return this . Register ( typeof ( TRegister ) , factory , name ) ;
}
/// <summary>
/// Register multiple implementations of a type.
///
/// Internally this registers each implementation using the full name of the class as its registration name.
/// </summary>
/// <typeparam name="TRegister">Type that each implementation implements.</typeparam>
/// <param name="implementationTypes">Types that implement RegisterType.</param>
/// <returns>MultiRegisterOptions for the fluent API.</returns>
public MultiRegisterOptions RegisterMultiple < TRegister > ( IEnumerable < Type > implementationTypes ) = > this . RegisterMultiple ( typeof ( TRegister ) , implementationTypes ) ;
/// <summary>
/// Register multiple implementations of a type.
///
/// Internally this registers each implementation using the full name of the class as its registration name.
/// </summary>
/// <param name="registrationType">Type that each implementation implements.</param>
/// <param name="implementationTypes">Types that implement RegisterType.</param>
/// <returns>MultiRegisterOptions for the fluent API.</returns>
public MultiRegisterOptions RegisterMultiple ( Type registrationType , IEnumerable < Type > implementationTypes ) {
if ( implementationTypes = = null ) {
throw new ArgumentNullException ( nameof ( implementationTypes ) , "types is null." ) ;
}
foreach ( Type type in implementationTypes . Where ( type = > ! registrationType . IsAssignableFrom ( type ) ) ) {
throw new ArgumentException ( $"types: The type {registrationType.FullName} is not assignable from {type.FullName}" ) ;
}
if ( implementationTypes . Count ( ) ! = implementationTypes . Distinct ( ) . Count ( ) ) {
IEnumerable < String > queryForDuplicatedTypes = implementationTypes . GroupBy ( i = > i ) . Where ( j = > j . Count ( ) > 1 ) . Select ( j = > j . Key . FullName ) ;
String fullNamesOfDuplicatedTypes = String . Join ( ",\n" , queryForDuplicatedTypes . ToArray ( ) ) ;
throw new ArgumentException ( $"types: The same implementation type cannot be specified multiple times for {registrationType.FullName}\n\n{fullNamesOfDuplicatedTypes}" ) ;
}
List < RegisterOptions > registerOptions = implementationTypes . Select ( type = > this . Register ( registrationType , type , type . FullName ) ) . ToList ( ) ;
return new MultiRegisterOptions ( registerOptions ) ;
}
#endregion
#region Unregistration
/// <summary>
/// Remove a named container class registration.
/// </summary>
/// <typeparam name="TRegister">Type to unregister.</typeparam>
/// <param name="name">Name of registration.</param>
/// <returns><c>true</c> if the registration is successfully found and removed; otherwise, <c>false</c>.</returns>
public Boolean Unregister < TRegister > ( String name = "" ) = > this . Unregister ( typeof ( TRegister ) , name ) ;
/// <summary>
/// Remove a named container class registration.
/// </summary>
/// <param name="registerType">Type to unregister.</param>
/// <param name="name">Name of registration.</param>
/// <returns><c>true</c> if the registration is successfully found and removed; otherwise, <c>false</c>.</returns>
public Boolean Unregister ( Type registerType , String name = "" ) = > this . RegisteredTypes . RemoveRegistration ( new TypeRegistration ( registerType , name ) ) ;
#endregion
#region Resolution
/// <summary>
/// Attempts to resolve a named type using specified options and the supplied constructor parameters.
///
/// Parameters are used in conjunction with normal container resolution to find the most suitable constructor (if one exists).
/// All user supplied parameters must exist in at least one resolvable constructor of RegisterType or resolution will fail.
/// </summary>
/// <param name="resolveType">Type to resolve.</param>
/// <param name="name">Name of registration.</param>
/// <param name="options">Resolution options.</param>
/// <returns>Instance of type.</returns>
/// <exception cref="DependencyContainerResolutionException">Unable to resolve the type.</exception>
public Object Resolve ( Type resolveType , String name = null , DependencyContainerResolveOptions options = null ) = > this . RegisteredTypes . ResolveInternal ( new TypeRegistration ( resolveType , name ) , options ? ? DependencyContainerResolveOptions . Default ) ;
/// <summary>
/// Attempts to resolve a named type using specified options and the supplied constructor parameters.
///
/// Parameters are used in conjunction with normal container resolution to find the most suitable constructor (if one exists).
/// All user supplied parameters must exist in at least one resolvable constructor of RegisterType or resolution will fail.
/// </summary>
/// <typeparam name="TResolveType">Type to resolve.</typeparam>
/// <param name="name">Name of registration.</param>
/// <param name="options">Resolution options.</param>
/// <returns>Instance of type.</returns>
/// <exception cref="DependencyContainerResolutionException">Unable to resolve the type.</exception>
public TResolveType Resolve < TResolveType > ( String name = null , DependencyContainerResolveOptions options = null ) where TResolveType : class = > ( TResolveType ) this . Resolve ( typeof ( TResolveType ) , name , options ) ;
/// <summary>
/// Attempts to predict whether a given type can be resolved with the supplied constructor parameters options.
/// Parameters are used in conjunction with normal container resolution to find the most suitable constructor (if one exists).
/// All user supplied parameters must exist in at least one resolvable constructor of RegisterType or resolution will fail.
/// Note: Resolution may still fail if user defined factory registrations fail to construct objects when called.
/// </summary>
/// <param name="resolveType">Type to resolve.</param>
/// <param name="name">The name.</param>
/// <param name="options">Resolution options.</param>
/// <returns>
/// Bool indicating whether the type can be resolved.
/// </returns>
public Boolean CanResolve ( Type resolveType , String name = null , DependencyContainerResolveOptions options = null ) = > this . RegisteredTypes . CanResolve ( new TypeRegistration ( resolveType , name ) , options ) ;
/// <summary>
/// Attempts to predict whether a given named type can be resolved with the supplied constructor parameters options.
///
/// Parameters are used in conjunction with normal container resolution to find the most suitable constructor (if one exists).
/// All user supplied parameters must exist in at least one resolvable constructor of RegisterType or resolution will fail.
///
/// Note: Resolution may still fail if user defined factory registrations fail to construct objects when called.
/// </summary>
/// <typeparam name="TResolveType">Type to resolve.</typeparam>
/// <param name="name">Name of registration.</param>
/// <param name="options">Resolution options.</param>
/// <returns>Bool indicating whether the type can be resolved.</returns>
public Boolean CanResolve < TResolveType > ( String name = null , DependencyContainerResolveOptions options = null ) where TResolveType : class = > this . CanResolve ( typeof ( TResolveType ) , name , options ) ;
/// <summary>
/// Attempts to resolve a type using the default options.
/// </summary>
/// <param name="resolveType">Type to resolve.</param>
/// <param name="resolvedType">Resolved type or default if resolve fails.</param>
/// <returns><c>true</c> if resolved successfully, <c>false</c> otherwise.</returns>
public Boolean TryResolve ( Type resolveType , out Object resolvedType ) {
try {
resolvedType = this . Resolve ( resolveType ) ;
return true ;
} catch ( DependencyContainerResolutionException ) {
resolvedType = null ;
return false ;
}
}
/// <summary>
/// Attempts to resolve a type using the given options.
/// </summary>
/// <param name="resolveType">Type to resolve.</param>
/// <param name="options">Resolution options.</param>
/// <param name="resolvedType">Resolved type or default if resolve fails.</param>
/// <returns><c>true</c> if resolved successfully, <c>false</c> otherwise.</returns>
public Boolean TryResolve ( Type resolveType , DependencyContainerResolveOptions options , out Object resolvedType ) {
try {
resolvedType = this . Resolve ( resolveType , options : options ) ;
return true ;
} catch ( DependencyContainerResolutionException ) {
resolvedType = null ;
return false ;
}
}
/// <summary>
/// Attempts to resolve a type using the default options and given name.
/// </summary>
/// <param name="resolveType">Type to resolve.</param>
/// <param name="name">Name of registration.</param>
/// <param name="resolvedType">Resolved type or default if resolve fails.</param>
/// <returns><c>true</c> if resolved successfully, <c>false</c> otherwise.</returns>
public Boolean TryResolve ( Type resolveType , String name , out Object resolvedType ) {
try {
resolvedType = this . Resolve ( resolveType , name ) ;
return true ;
} catch ( DependencyContainerResolutionException ) {
resolvedType = null ;
return false ;
}
}
/// <summary>
/// Attempts to resolve a type using the given options and name.
/// </summary>
/// <param name="resolveType">Type to resolve.</param>
/// <param name="name">Name of registration.</param>
/// <param name="options">Resolution options.</param>
/// <param name="resolvedType">Resolved type or default if resolve fails.</param>
/// <returns><c>true</c> if resolved successfully, <c>false</c> otherwise.</returns>
public Boolean TryResolve ( Type resolveType , String name , DependencyContainerResolveOptions options , out Object resolvedType ) {
try {
resolvedType = this . Resolve ( resolveType , name , options ) ;
return true ;
} catch ( DependencyContainerResolutionException ) {
resolvedType = null ;
return false ;
}
}
/// <summary>
/// Attempts to resolve a type using the default options.
/// </summary>
/// <typeparam name="TResolveType">Type to resolve.</typeparam>
/// <param name="resolvedType">Resolved type or default if resolve fails.</param>
/// <returns><c>true</c> if resolved successfully, <c>false</c> otherwise.</returns>
public Boolean TryResolve < TResolveType > ( out TResolveType resolvedType ) where TResolveType : class {
try {
resolvedType = this . Resolve < TResolveType > ( ) ;
return true ;
} catch ( DependencyContainerResolutionException ) {
resolvedType = default ;
return false ;
}
}
/// <summary>
/// Attempts to resolve a type using the given options.
/// </summary>
/// <typeparam name="TResolveType">Type to resolve.</typeparam>
/// <param name="options">Resolution options.</param>
/// <param name="resolvedType">Resolved type or default if resolve fails.</param>
/// <returns><c>true</c> if resolved successfully, <c>false</c> otherwise.</returns>
public Boolean TryResolve < TResolveType > ( DependencyContainerResolveOptions options , out TResolveType resolvedType ) where TResolveType : class {
try {
resolvedType = this . Resolve < TResolveType > ( options : options ) ;
return true ;
} catch ( DependencyContainerResolutionException ) {
resolvedType = default ;
return false ;
}
}
/// <summary>
/// Attempts to resolve a type using the default options and given name.
/// </summary>
/// <typeparam name="TResolveType">Type to resolve.</typeparam>
/// <param name="name">Name of registration.</param>
/// <param name="resolvedType">Resolved type or default if resolve fails.</param>
/// <returns><c>true</c> if resolved successfully, <c>false</c> otherwise.</returns>
public Boolean TryResolve < TResolveType > ( String name , out TResolveType resolvedType ) where TResolveType : class {
try {
resolvedType = this . Resolve < TResolveType > ( name ) ;
return true ;
} catch ( DependencyContainerResolutionException ) {
resolvedType = default ;
return false ;
}
}
/// <summary>
/// Attempts to resolve a type using the given options and name.
/// </summary>
/// <typeparam name="TResolveType">Type to resolve.</typeparam>
/// <param name="name">Name of registration.</param>
/// <param name="options">Resolution options.</param>
/// <param name="resolvedType">Resolved type or default if resolve fails.</param>
/// <returns><c>true</c> if resolved successfully, <c>false</c> otherwise.</returns>
public Boolean TryResolve < TResolveType > ( String name , DependencyContainerResolveOptions options , out TResolveType resolvedType ) where TResolveType : class {
try {
resolvedType = this . Resolve < TResolveType > ( name , options ) ;
return true ;
} catch ( DependencyContainerResolutionException ) {
resolvedType = default ;
return false ;
}
}
/// <summary>
/// Returns all registrations of a type.
/// </summary>
/// <param name="resolveType">Type to resolveAll.</param>
/// <param name="includeUnnamed">Whether to include un-named (default) registrations.</param>
/// <returns>IEnumerable.</returns>
public IEnumerable < Object > ResolveAll ( Type resolveType , Boolean includeUnnamed = false ) = > this . RegisteredTypes . Resolve ( resolveType , includeUnnamed ) ;
/// <summary>
/// Returns all registrations of a type.
/// </summary>
/// <typeparam name="TResolveType">Type to resolveAll.</typeparam>
/// <param name="includeUnnamed">Whether to include un-named (default) registrations.</param>
/// <returns>IEnumerable.</returns>
public IEnumerable < TResolveType > ResolveAll < TResolveType > ( Boolean includeUnnamed = true ) where TResolveType : class = > this . ResolveAll ( typeof ( TResolveType ) , includeUnnamed ) . Cast < TResolveType > ( ) ;
/// <summary>
/// Attempts to resolve all public property dependencies on the given object using the given resolve options.
/// </summary>
/// <param name="input">Object to "build up".</param>
/// <param name="resolveOptions">Resolve options to use.</param>
public void BuildUp ( Object input , DependencyContainerResolveOptions resolveOptions = null ) {
if ( resolveOptions = = null ) {
resolveOptions = DependencyContainerResolveOptions . Default ;
}
IEnumerable < PropertyInfo > properties = input . GetType ( ) . GetProperties ( ) . Where ( property = > property . GetCacheGetMethod ( ) ! = null & & property . GetCacheSetMethod ( ) ! = null & & ! property . PropertyType . IsValueType ) ;
foreach ( PropertyInfo property in properties . Where ( property = > property . GetValue ( input , null ) = = null ) ) {
try {
property . SetValue ( input , this . RegisteredTypes . ResolveInternal ( new TypeRegistration ( property . PropertyType ) , resolveOptions ) , null ) ;
} catch ( DependencyContainerResolutionException ) {
// Catch any resolution errors and ignore them
}
}
}
#endregion
#region Internal Methods
internal static Boolean IsValidAssignment ( Type registerType , Type registerImplementation ) {
if ( ! registerType . IsGenericTypeDefinition ) {
if ( ! registerType . IsAssignableFrom ( registerImplementation ) ) {
return false ;
}
} else {
if ( registerType . IsInterface & & registerImplementation . GetInterfaces ( ) . All ( t = > t . Name ! = registerType . Name ) ) {
return false ;
}
if ( registerType . IsAbstract & & registerImplementation . BaseType ! = registerType ) {
return false ;
}
}
return true ;
}
private static Boolean IsIgnoredAssembly ( Assembly assembly ) {
// TODO - find a better way to remove "system" assemblies from the auto registration
List < Func < Assembly , Boolean > > ignoreChecks = new List < Func < Assembly , Boolean > >
{
2019-12-04 18:57:18 +01:00
asm = > asm . FullName . StartsWith ( "Microsoft." , StringComparison . Ordinal ) ,
asm = > asm . FullName . StartsWith ( "System." , StringComparison . Ordinal ) ,
asm = > asm . FullName . StartsWith ( "System," , StringComparison . Ordinal ) ,
asm = > asm . FullName . StartsWith ( "CR_ExtUnitTest" , StringComparison . Ordinal ) ,
asm = > asm . FullName . StartsWith ( "mscorlib," , StringComparison . Ordinal ) ,
asm = > asm . FullName . StartsWith ( "CR_VSTest" , StringComparison . Ordinal ) ,
asm = > asm . FullName . StartsWith ( "DevExpress.CodeRush" , StringComparison . Ordinal ) ,
asm = > asm . FullName . StartsWith ( "xunit." , StringComparison . Ordinal ) ,
2019-12-08 21:23:54 +01:00
} ;
return ignoreChecks . Any ( check = > check ( assembly ) ) ;
}
private static Boolean IsIgnoredType ( Type type , Func < Type , Boolean > registrationPredicate ) {
// TODO - find a better way to remove "system" types from the auto registration
List < Func < Type , Boolean > > ignoreChecks = new List < Func < Type , Boolean > > ( )
{
2019-12-04 18:57:18 +01:00
t = > t . FullName ? . StartsWith ( "System." , StringComparison . Ordinal ) ? ? false ,
t = > t . FullName ? . StartsWith ( "Microsoft." , StringComparison . Ordinal ) ? ? false ,
t = > t . IsPrimitive ,
t = > t . IsGenericTypeDefinition ,
2019-12-08 21:23:54 +01:00
t = > t . GetConstructors ( BindingFlags . Instance | BindingFlags . Public ) . Length = = 0 & &
2019-12-04 18:57:18 +01:00
! ( t . IsInterface | | t . IsAbstract ) ,
2019-12-08 21:23:54 +01:00
} ;
if ( registrationPredicate ! = null ) {
ignoreChecks . Add ( t = > ! registrationPredicate ( t ) ) ;
}
return ignoreChecks . Any ( check = > check ( type ) ) ;
}
private static ObjectFactoryBase GetDefaultObjectFactory ( Type registerType , Type registerImplementation ) = > registerType . IsInterface | | registerType . IsAbstract ? ( ObjectFactoryBase ) new SingletonFactory ( registerType , registerImplementation ) : new MultiInstanceFactory ( registerType , registerImplementation ) ;
#endregion
}
2019-12-04 18:57:18 +01:00
}