using System ;
using System.Collections.Generic ;
using System.Globalization ;
using System.Linq ;
using System.Reflection ;
using System.Threading ;
using ZeroLevel.Services.Collections ;
namespace ZeroLevel.Patterns.DependencyInjection
{
internal sealed class Container :
IContainer
{
#region Activator
private static object Activate ( Type type , object [ ] args )
{
var flags = BindingFlags . NonPublic | BindingFlags . Instance | BindingFlags . Public ;
CultureInfo culture = null ; // use InvariantCulture or other if you prefer
return Activator . CreateInstance ( type , flags , null , args , culture ) ;
}
public T CreateInstance < T > ( string resolveName = "" )
{
T instance = default ( T ) ;
try
{
instance = Resolve < T > ( resolveName ) ;
}
catch
{
instance = ( T ) Activate ( typeof ( T ) , null ) ;
}
Compose ( instance ) ;
return instance ;
}
public T CreateInstance < T > ( object [ ] args , string resolveName = "" )
{
T instance = default ( T ) ;
try
{
instance = Resolve < T > ( resolveName , args ) ;
}
catch
{
instance = ( T ) Activate ( typeof ( T ) , args ) ;
}
Compose ( instance ) ;
return instance ;
}
public object CreateInstance ( Type type , string resolveName = "" )
{
object instance = null ;
try
{
instance = Resolve ( type , resolveName ) ;
}
catch
{
instance = Activate ( type , null ) ;
}
Compose ( instance ) ;
return instance ;
}
public object CreateInstance ( Type type , object [ ] args , string resolveName = "" )
{
object instance = null ;
try
{
instance = Resolve ( type , resolveName , args ) ;
}
catch
{
instance = Activate ( type , args ) ;
}
Compose ( instance ) ;
return instance ;
}
# endregion
#region Caching
private readonly ReaderWriterLockSlim _rwLock =
new ReaderWriterLockSlim ( ) ;
/// <summary>
/// Map - contract - dependency resolving
/// </summary>
private readonly Dictionary < Type , List < ResolveTypeInfo > > _resolvingMap =
new Dictionary < Type , List < ResolveTypeInfo > > ( ) ;
private readonly object _constructorCacheeLocker = new object ( ) ;
/// <summary>
/// Types constructors cache
/// </summary>
private readonly Dictionary < Type , IEnumerable < ConstructorMetadata > > _constructorCachee =
new Dictionary < Type , IEnumerable < ConstructorMetadata > > ( ) ;
# endregion
#region Private
/// <summary>
/// Creating an instance of an object at the specified dependency resolution
/// </summary>
/// <param name="resolveType">Dependency resolving metadata</param>
/// <param name="args">Ctor args</param>
/// <returns>Instance</returns>
private object MakeResolving ( ResolveTypeInfo resolveType , object [ ] args , bool compose = true )
{
Type instanceType = resolveType . ImplementationType ;
if ( resolveType . IsShared )
{
if ( null = = resolveType . SharedInstance )
{
resolveType . SharedInstance = MakeInstance ( instanceType , args ? ? resolveType . ConstructorParameters ) ;
if ( compose )
{
Compose ( resolveType . SharedInstance ) ;
}
}
return resolveType . SharedInstance ;
}
var sessionInstance = MakeInstance ( instanceType , args ? ? resolveType . ConstructorParameters ) ;
if ( compose )
{
Compose ( sessionInstance ) ;
}
return sessionInstance ;
}
/// <summary>
/// Creating an instance of the object at the specified dependency resolution, for a generic type of contract
/// </summary>
/// <param name="resolveType">Dependency resolving metadata</param>
/// <param name="genericType">Generic contract</param>
/// <param name="args">Ctor args</param>
/// <returns>Instance</returns>
private object MakeGenericResolving ( ResolveTypeInfo resolveType , Type genericType , object [ ] args , bool compose = true )
{
if ( null = = resolveType . GenericCachee )
{
resolveType . GenericCachee = new Dictionary < Type , Type > ( ) ;
}
if ( false = = resolveType . GenericCachee . ContainsKey ( genericType ) )
{
var genericArgumentTypes = genericType . GetGenericArguments ( ) ;
var realType = resolveType . ImplementationType . MakeGenericType ( genericArgumentTypes ) ;
resolveType . GenericCachee . Add ( genericType , realType ) ;
}
Type instanceType = resolveType . GenericCachee [ genericType ] ;
if ( resolveType . IsShared )
{
if ( resolveType . GenericInstanceCachee = = null )
{
resolveType . GenericInstanceCachee = new Dictionary < Type , object > ( ) ;
}
if ( false = = resolveType . GenericInstanceCachee . ContainsKey ( instanceType ) )
{
var sharedInstance = MakeInstance ( instanceType , args ? ? resolveType . ConstructorParameters ) ;
if ( compose )
{
Compose ( sharedInstance ) ;
}
resolveType . GenericInstanceCachee . Add ( instanceType , sharedInstance ) ;
}
return resolveType . GenericInstanceCachee [ instanceType ] ;
}
var sessionInstance = MakeInstance ( instanceType , args ? ? resolveType . ConstructorParameters ) ;
if ( compose )
{
Compose ( sessionInstance ) ;
}
return sessionInstance ;
}
/// <summary>
/// Collecting properties of the type marked with attribute dependency resolution
/// </summary>
/// <param name="type">Type</param>
/// <returns>List of properties marked with "Resolve" attribute</returns>
private static IEnumerable < PropertyInfo > CollectResolvingProperties ( Type type )
{
return type . GetProperties ( BindingFlags . Instance | BindingFlags . NonPublic | BindingFlags . Public | BindingFlags . FlattenHierarchy ) .
Where ( p = > p . GetCustomAttribute < ResolveAttribute > ( ) ! = null ) ;
}
/// <summary>
/// Collecting fields of type marked with an attribute of dependency resolution
/// </summary>
/// <param name="type">Type</param>
/// <returns>List of properties marked with "Resolve" attribute</returns>
private static IEnumerable < FieldInfo > CollectResolvingFields ( Type type )
{
return type . GetFields ( BindingFlags . Instance | BindingFlags . NonPublic | BindingFlags . Public | BindingFlags . FlattenHierarchy ) .
Where ( p = > p . GetCustomAttribute < ResolveAttribute > ( ) ! = null ) ;
}
/// <summary>
/// Search for dependency resolution
/// </summary>
/// <param name="type">Contract</param>
/// <param name="resolveName">Dependency name</param>
/// <param name="contractType">Redefined contract type</param>
/// <returns></returns>
private ResolveTypeInfo FindResolving ( Type type , string resolveName , Type contractType )
{
HashSet < Type > contract_candidates = new HashSet < Type > ( ) ;
if ( contractType ! = null )
{
if ( contractType . IsInterface )
contract_candidates . Add ( contractType ) ;
foreach ( var c in GetInterfacesAndAbstracts ( contractType ) )
contract_candidates . Add ( c ) ;
}
if ( contract_candidates . Count = = 0 )
{
if ( type . IsInterface )
contract_candidates . Add ( type ) ;
foreach ( var c in GetInterfacesAndAbstracts ( type ) )
contract_candidates . Add ( c ) ;
}
if ( contract_candidates . Count > 0 )
{
try
{
_rwLock . EnterReadLock ( ) ;
var resolveInfo = _resolvingMap . Single ( r = > contract_candidates . Any ( ct = > ct = = r . Key ) ) ;
return resolveInfo . Value . First ( ri = > ri . ResolveKey . Equals ( resolveName , StringComparison . OrdinalIgnoreCase ) ) ;
}
finally
{
_rwLock . ExitReadLock ( ) ;
}
}
throw new KeyNotFoundException ( $"Can't resolve dependency by type '{type.FullName}' and dependency name '{resolveName}'" ) ;
}
/// <summary>
/// Resolving dependency on attribute "Resolve
/// </summary>
/// <param name="type">Contract</param>
/// <param name="resolveAttribute">Resolve attribute</param>
/// <returns>Instance</returns>
private object MakeInstanceBy ( Type type , ResolveAttribute resolveAttribute )
{
var is_generic = false ;
var maybyType = type ;
if ( maybyType . IsGenericTypeDefinition )
{
maybyType = maybyType . GetGenericTypeDefinition ( ) ;
is_generic = true ;
}
var resolveType = FindResolving ( maybyType ,
resolveAttribute ? . ResolveName ? ? string . Empty ,
resolveAttribute ? . ContractType ) ;
try
{
if ( is_generic )
return MakeGenericResolving ( resolveType , type , null ) ;
return MakeResolving ( resolveType , null ) ;
}
catch ( Exception ex )
{
throw new Exception ( $"Can't create type '{type.FullName}' instance for contract type {type.FullName}. Dependency key: '{resolveAttribute?.ResolveName}'" , ex ) ;
}
}
/// <summary>
/// Collection of interfaces and abstract classes from which the type is inherited
/// </summary>
/// <param name="sourceType">Type</param>
/// <returns>List of interfaces and abstract classes</returns>
private static IEnumerable < Type > GetInterfacesAndAbstracts ( Type sourceType )
{
var interfaces = sourceType . GetInterfaces ( ) . ToList ( ) ;
var parent = sourceType . BaseType ;
while ( parent ! = null & & parent ! = typeof ( object ) )
{
if ( parent . IsAbstract & & parent . IsClass )
interfaces . Add ( parent ) ;
parent = parent . BaseType ;
}
return interfaces ;
}
/// <summary>
/// Getting a list of metadata by type constructors
/// </summary>
/// <param name="type">Type</param>
/// <returns>Metadata type constructors</returns>
private IEnumerable < ConstructorMetadata > GetConstructors ( Type type )
{
lock ( _constructorCacheeLocker )
{
if ( false = = _constructorCachee . ContainsKey ( type ) )
{
var list = new List < ConstructorMetadata > ( ) ;
foreach ( var c in type .
GetConstructors ( BindingFlags . NonPublic | BindingFlags . Instance | BindingFlags . Public ) )
{
list . Add ( new ConstructorMetadata ( this , c ) ) ;
}
_constructorCachee . Add ( type , list ) ;
}
}
return _constructorCachee [ type ] ;
}
/// <summary>
/// Creating an instance of an object, including with non-public constructors
/// </summary>
/// <param name="type">Type</param>
/// <param name="args">Ctor args</param>
/// <returns>Instance</returns>
private object MakeInstance ( Type type , object [ ] args )
{
ConstructorInfo constructor = null ;
object [ ] parameters = null ;
foreach ( var ctor in GetConstructors ( type ) )
{
if ( ctor . IsMatch ( args , out parameters ) )
{
constructor = ctor . Constructor ;
break ;
}
}
if ( null = = constructor )
{
return System . Runtime . Serialization . FormatterServices . GetUninitializedObject ( type ) ;
}
else
{
return constructor . Invoke ( parameters ) ;
/ * var flags = BindingFlags . NonPublic | BindingFlags . Instance | BindingFlags . Public ;
CultureInfo culture = null ; // use InvariantCulture or other if you prefer
return Activator . CreateInstance ( type , flags , null , args , culture ) ; * /
}
}
/// <summary>
/// Dependency resolution registration
/// </summary>
/// <param name="contractType">Contract</param>
/// <param name="resolveType">Dependency resolving metadata</param>
private void Register ( Type contractType , ResolveTypeInfo resolveType )
{
try
{
_rwLock . EnterUpgradeableReadLock ( ) ;
if ( false = = _resolvingMap . ContainsKey ( contractType ) )
{
try
{
_rwLock . EnterWriteLock ( ) ;
_resolvingMap . Add ( contractType , new List < ResolveTypeInfo > ( ) ) ;
}
finally
{
_rwLock . ExitWriteLock ( ) ;
}
}
else
{
if ( resolveType . IsDefault & &
_resolvingMap [ contractType ] . Any ( it = > it . IsDefault ) )
{
throw new Exception ( $"Default resolve type already has been defined. Contract: {contractType.FullName}" ) ;
}
if ( _resolvingMap [ contractType ] .
Any ( it = > it . ResolveKey . Equals ( resolveType . ResolveKey , StringComparison . OrdinalIgnoreCase ) ) )
{
throw new Exception ( $"Resolve type with the same name '{resolveType.ResolveKey}' already has been defined. Contract: { contractType.FullName}" ) ;
}
}
try
{
_rwLock . EnterWriteLock ( ) ;
_resolvingMap [ contractType ] . Add ( resolveType ) ;
}
finally
{
_rwLock . ExitWriteLock ( ) ;
}
}
finally
{
_rwLock . ExitUpgradeableReadLock ( ) ;
}
}
# endregion
#region Register
public void Register < TContract , TImplementation > ( )
{
var resolveType = new ResolveTypeInfo
{
ImplementationType = typeof ( TImplementation ) ,
IsDefault = true ,
IsShared = false ,
ResolveKey = string . Empty
} ;
Register ( typeof ( TContract ) , resolveType ) ;
}
public void Register < TContract , TImplementation > ( bool shared )
{
var resolveType = new ResolveTypeInfo
{
ImplementationType = typeof ( TImplementation ) ,
IsDefault = true ,
IsShared = shared ,
ResolveKey = string . Empty
} ;
Register ( typeof ( TContract ) , resolveType ) ;
}
public void Register < TContract , TImplementation > ( string resolveName )
{
var resolveType = new ResolveTypeInfo
{
ImplementationType = typeof ( TImplementation ) ,
IsDefault = string . IsNullOrWhiteSpace ( resolveName ) ,
IsShared = false ,
ResolveKey = resolveName ? . Trim ( )
} ;
Register ( typeof ( TContract ) , resolveType ) ;
}
public void Register < TContract , TImplementation > ( string resolveName , bool shared )
{
var resolveType = new ResolveTypeInfo
{
ImplementationType = typeof ( TImplementation ) ,
IsDefault = string . IsNullOrWhiteSpace ( resolveName ) ,
IsShared = shared ,
ResolveKey = resolveName ? . Trim ( )
} ;
Register ( typeof ( TContract ) , resolveType ) ;
}
public void Register ( Type contractType , Type implementationType )
{
var resolveType = new ResolveTypeInfo
{
ImplementationType = implementationType ,
IsDefault = true ,
IsShared = false ,
ResolveKey = string . Empty
} ;
Register ( contractType , resolveType ) ;
}
public void Register ( Type contractType , Type implementationType , string resolveName )
{
var resolveType = new ResolveTypeInfo
{
ImplementationType = implementationType ,
IsDefault = string . IsNullOrWhiteSpace ( resolveName ) ,
IsShared = false ,
ResolveKey = resolveName ? . Trim ( )
} ;
Register ( contractType , resolveType ) ;
}
public void Register ( Type contractType , Type implementationType , bool shared )
{
var resolveType = new ResolveTypeInfo
{
ImplementationType = implementationType ,
IsDefault = true ,
IsShared = shared ,
ResolveKey = string . Empty
} ;
Register ( contractType , resolveType ) ;
}
public void Register ( Type contractType , Type implementationType , string resolveName , bool shared )
{
var resolveType = new ResolveTypeInfo
{
ImplementationType = implementationType ,
IsDefault = string . IsNullOrWhiteSpace ( resolveName ) ,
IsShared = shared ,
ResolveKey = resolveName ? . Trim ( )
} ;
Register ( contractType , resolveType ) ;
}
#endregion
#region Register with parameters
public void ParameterizedRegister < TContract , TImplementation > ( object [ ] constructorParameters )
{
var resolveType = new ResolveTypeInfo
{
ImplementationType = typeof ( TImplementation ) ,
IsDefault = true ,
IsShared = false ,
ResolveKey = string . Empty ,
ConstructorParameters = constructorParameters
} ;
Register ( typeof ( TContract ) , resolveType ) ;
}
public void ParameterizedRegister < TContract , TImplementation > ( string resolveName , object [ ] constructorParameters )
{
var resolveType = new ResolveTypeInfo
{
ImplementationType = typeof ( TImplementation ) ,
IsDefault = string . IsNullOrWhiteSpace ( resolveName ) ,
IsShared = false ,
ResolveKey = resolveName ? . Trim ( ) ,
ConstructorParameters = constructorParameters
} ;
Register ( typeof ( TContract ) , resolveType ) ;
}
public void ParameterizedRegister < TContract , TImplementation > ( bool shared , object [ ] constructorParameters )
{
var resolveType = new ResolveTypeInfo
{
ImplementationType = typeof ( TImplementation ) ,
IsDefault = true ,
IsShared = shared ,
ResolveKey = string . Empty ,
ConstructorParameters = constructorParameters
} ;
Register ( typeof ( TContract ) , resolveType ) ;
}
public void ParameterizedRegister < TContract , TImplementation > ( string resolveName , bool shared , object [ ] constructorParameters )
{
var resolveType = new ResolveTypeInfo
{
ImplementationType = typeof ( TImplementation ) ,
IsDefault = string . IsNullOrWhiteSpace ( resolveName ) ,
IsShared = shared ,
ResolveKey = resolveName ? . Trim ( ) ,
ConstructorParameters = constructorParameters
} ;
Register ( typeof ( TContract ) , resolveType ) ;
}
public void ParameterizedRegister ( Type contractType , Type implementationType , object [ ] constructorParameters )
{
var resolveType = new ResolveTypeInfo
{
ImplementationType = implementationType ,
IsDefault = true ,
IsShared = false ,
ResolveKey = string . Empty ,
ConstructorParameters = constructorParameters
} ;
Register ( contractType , resolveType ) ;
}
public void ParameterizedRegister ( Type contractType , Type implementationType , string resolveName , object [ ] constructorParameters )
{
var resolveType = new ResolveTypeInfo
{
ImplementationType = implementationType ,
IsDefault = string . IsNullOrWhiteSpace ( resolveName ) ,
IsShared = false ,
ResolveKey = resolveName ? . Trim ( ) ,
ConstructorParameters = constructorParameters
} ;
Register ( contractType , resolveType ) ;
}
public void ParameterizedRegister ( Type contractType , Type implementationType , bool shared , object [ ] constructorParameters )
{
var resolveType = new ResolveTypeInfo
{
ImplementationType = implementationType ,
IsDefault = true ,
IsShared = shared ,
ResolveKey = string . Empty ,
ConstructorParameters = constructorParameters
} ;
Register ( contractType , resolveType ) ;
}
public void ParameterizedRegister ( Type contractType , Type implementationType , string resolveName , bool shared , object [ ] constructorParameters )
{
var resolveType = new ResolveTypeInfo
{
ImplementationType = implementationType ,
IsDefault = string . IsNullOrWhiteSpace ( resolveName ) ,
IsShared = shared ,
ResolveKey = resolveName ? . Trim ( ) ,
ConstructorParameters = constructorParameters
} ;
Register ( contractType , resolveType ) ;
}
# endregion
#region Register instance
/// <summary>
/// Register singletone
/// </summary>
/// <typeparam name="TContract">Contract</typeparam>
/// <param name="implementation">Instance</param>
public void Register < TContract > ( TContract implementation )
{
var resolveType = new ResolveTypeInfo
{
ImplementationType = implementation . GetType ( ) ,
IsDefault = true ,
IsShared = true ,
ResolveKey = string . Empty ,
SharedInstance = implementation
} ;
Register ( typeof ( TContract ) , resolveType ) ;
}
public void Register ( Type contractType , object implementation )
{
var resolveType = new ResolveTypeInfo
{
ImplementationType = implementation . GetType ( ) ,
IsDefault = true ,
IsShared = true ,
ResolveKey = string . Empty ,
SharedInstance = implementation
} ;
Register ( contractType , resolveType ) ;
}
public void Register < TContract > ( TContract implementation , string resolveName )
{
var resolveType = new ResolveTypeInfo
{
ImplementationType = implementation . GetType ( ) ,
IsDefault = string . IsNullOrEmpty ( resolveName ) ,
IsShared = true ,
ResolveKey = resolveName ,
SharedInstance = implementation
} ;
Register ( typeof ( TContract ) , resolveType ) ;
}
public void Register ( Type contractType , string resolveName , object implementation )
{
var resolveType = new ResolveTypeInfo
{
ImplementationType = implementation . GetType ( ) ,
IsDefault = true ,
IsShared = true ,
ResolveKey = resolveName ,
SharedInstance = implementation
} ;
Register ( contractType , resolveType ) ;
}
# endregion
#region Safe register
public bool TryRegister < TContract , TImplementation > ( Action < Exception > fallback = null )
{
try
{
Register < TContract , TImplementation > ( ) ;
return true ;
}
catch ( Exception ex )
{
fallback ? . Invoke ( ex ) ;
return false ;
}
}
public bool TryRegister < TContract , TImplementation > ( bool shared , Action < Exception > fallback = null )
{
try
{
Register < TContract , TImplementation > ( shared ) ;
return true ;
}
catch ( Exception ex )
{
fallback ? . Invoke ( ex ) ;
return false ;
}
}
public bool TryRegister < TContract , TImplementation > ( string resolveName , Action < Exception > fallback = null )
{
try
{
Register < TContract , TImplementation > ( resolveName ) ;
return true ;
}
catch ( Exception ex )
{
fallback ? . Invoke ( ex ) ;
return false ;
}
}
public bool TryRegister < TContract , TImplementation > ( string resolveName , bool shared , Action < Exception > fallback = null )
{
try
{
Register < TContract , TImplementation > ( resolveName , shared ) ;
return true ;
}
catch ( Exception ex )
{
fallback ? . Invoke ( ex ) ;
return false ;
}
}
public bool TryRegister ( Type contractType , Type implementationType , Action < Exception > fallback = null )
{
try
{
Register ( contractType , implementationType ) ;
return true ;
}
catch ( Exception ex )
{
fallback ? . Invoke ( ex ) ;
return false ;
}
}
public bool TryRegister ( Type contractType , Type implementationType , string resolveName , Action < Exception > fallback = null )
{
try
{
Register ( contractType , implementationType , resolveName ) ;
return true ;
}
catch ( Exception ex )
{
fallback ? . Invoke ( ex ) ;
return false ;
}
}
public bool TryRegister ( Type contractType , Type implementationType , bool shared , Action < Exception > fallback = null )
{
try
{
Register ( contractType , implementationType , shared ) ;
return true ;
}
catch ( Exception ex )
{
fallback ? . Invoke ( ex ) ;
return false ;
}
}
public bool TryRegister ( Type contractType , Type implementationType , string resolveName , bool shared , Action < Exception > fallback = null )
{
try
{
Register ( contractType , implementationType , resolveName , shared ) ;
return true ;
}
catch ( Exception ex )
{
fallback ? . Invoke ( ex ) ;
return false ;
}
}
# endregion
#region Safe register with parameters
public bool TryParameterizedRegister < TContract , TImplementation > ( object [ ] constructorParameters , Action < Exception > fallback = null )
{
try
{
ParameterizedRegister < TContract , TImplementation > ( constructorParameters ) ;
return true ;
}
catch ( Exception ex )
{
fallback ? . Invoke ( ex ) ;
return false ;
}
}
public bool TryParameterizedRegister < TContract , TImplementation > ( string resolveName , object [ ] constructorParameters , Action < Exception > fallback = null )
{
try
{
ParameterizedRegister < TContract , TImplementation > ( resolveName , constructorParameters ) ;
return true ;
}
catch ( Exception ex )
{
fallback ? . Invoke ( ex ) ;
return false ;
}
}
public bool TryParameterizedRegister < TContract , TImplementation > ( bool shared , object [ ] constructorParameters , Action < Exception > fallback = null )
{
try
{
ParameterizedRegister < TContract , TImplementation > ( shared , constructorParameters ) ;
return true ;
}
catch ( Exception ex )
{
fallback ? . Invoke ( ex ) ;
return false ;
}
}
public bool TryParameterizedRegister < TContract , TImplementation > ( string resolveName , bool shared , object [ ] constructorParameters , Action < Exception > fallback = null )
{
try
{
ParameterizedRegister < TContract , TImplementation > ( resolveName , shared , constructorParameters ) ;
return true ;
}
catch ( Exception ex )
{
fallback ? . Invoke ( ex ) ;
return false ;
}
}
public bool TryParameterizedRegister ( Type contractType , Type implementationType , object [ ] constructorParameters , Action < Exception > fallback = null )
{
try
{
ParameterizedRegister ( contractType , implementationType , constructorParameters ) ;
return true ;
}
catch ( Exception ex )
{
fallback ? . Invoke ( ex ) ;
return false ;
}
}
public bool TryParameterizedRegister ( Type contractType , Type implementationType , string resolveName , object [ ] constructorParameters , Action < Exception > fallback = null )
{
try
{
ParameterizedRegister ( contractType , implementationType , resolveName , constructorParameters ) ;
return true ;
}
catch ( Exception ex )
{
fallback ? . Invoke ( ex ) ;
return false ;
}
}
public bool TryParameterizedRegister ( Type contractType , Type implementationType , bool shared , object [ ] constructorParameters , Action < Exception > fallback = null )
{
try
{
ParameterizedRegister ( contractType , implementationType , shared , constructorParameters ) ;
return true ;
}
catch ( Exception ex )
{
fallback ? . Invoke ( ex ) ;
return false ;
}
}
public bool TryParameterizedRegister ( Type contractType , Type implementationType , string resolveName , bool shared , object [ ] constructorParameters , Action < Exception > fallback = null )
{
try
{
ParameterizedRegister ( contractType , implementationType , resolveName , shared , constructorParameters ) ;
return true ;
}
catch ( Exception ex )
{
fallback ? . Invoke ( ex ) ;
return false ;
}
}
# endregion
#region Resolving
public object Resolve ( Type type , bool compose = true )
{
return Resolve ( type , string . Empty , null , compose ) ;
}
public object Resolve ( Type type , object [ ] args , bool compose = true )
{
return Resolve ( type , string . Empty , args , compose ) ;
}
public object Resolve ( Type type , string resolveName , bool compose = true )
{
return Resolve ( type , resolveName , null , compose ) ;
}
public T Resolve < T > ( bool compose = true )
{
return ( T ) Resolve ( typeof ( T ) , string . Empty , null , compose ) ;
}
public T Resolve < T > ( object [ ] args , bool compose = true )
{
return ( T ) Resolve ( typeof ( T ) , string . Empty , args , compose ) ;
}
public T Resolve < T > ( string resolveName , bool compose = true )
{
return ( T ) Resolve ( typeof ( T ) , resolveName , null , compose ) ;
}
public T Resolve < T > ( string resolveName , object [ ] args , bool compose = true )
{
return ( T ) Resolve ( typeof ( T ) , resolveName , args , compose ) ;
}
public bool IsResolvingExists < T > ( )
{
return IsResolvingExists ( typeof ( T ) , string . Empty ) ;
}
public bool IsResolvingExists < T > ( string resolveName )
{
return IsResolvingExists ( typeof ( T ) , resolveName ) ;
}
public bool IsResolvingExists ( Type type )
{
return IsResolvingExists ( type , string . Empty ) ;
}
public bool IsResolvingExists ( Type type , string resolveName )
{
return GetResolvedType ( type , resolveName ) ? . Item1 ! = null ;
}
private Tuple < ResolveTypeInfo , bool > GetResolvedType ( Type type , string resolveName )
{
try
{
_rwLock . EnterReadLock ( ) ;
if ( _resolvingMap . ContainsKey ( type ) )
{
return Tuple . Create ( _resolvingMap [ type ] .
FirstOrDefault ( i = > i . ResolveKey . Equals ( resolveName , StringComparison . Ordinal ) ) ,
false ) ;
}
else if ( type . IsGenericType )
{
var generic_type = type . GetGenericTypeDefinition ( ) ;
if ( _resolvingMap . ContainsKey ( generic_type ) )
{
return Tuple . Create ( _resolvingMap [ generic_type ] .
FirstOrDefault ( i = > i . ResolveKey . Equals ( resolveName , StringComparison . Ordinal ) ) ,
true ) ;
}
}
}
finally
{
_rwLock . ExitReadLock ( ) ;
}
return new Tuple < ResolveTypeInfo , bool > ( null , false ) ;
}
public object Resolve ( Type type , string resolveName , object [ ] args , bool compose = true )
{
var resolve = GetResolvedType ( type , resolveName ) ;
if ( null = = resolve . Item1 )
throw new KeyNotFoundException ( $"Can'r resolve type {type.FullName} on key '{resolveName}'" ) ;
// Detect instance type
try
{
if ( resolve . Item2 )
{
return MakeGenericResolving ( resolve . Item1 , type , args , compose ) ;
}
return MakeResolving ( resolve . Item1 , args , compose ) ;
}
catch ( Exception ex )
{
throw new Exception ( $"Can't create instance for type {type.FullName} for resolved dependency {type.FullName} by key {resolveName}" , ex ) ;
}
}
# endregion
#region Safe resolving
public object TryResolve ( Type type , out object result , bool compose = true )
{
return TryResolve ( type , string . Empty , null , out result , compose ) ;
}
public object TryResolve ( Type type , object [ ] args , out object result , bool compose = true )
{
return TryResolve ( type , string . Empty , args , out result , compose ) ;
}
public object TryResolve ( Type type , string resolveName , out object result , bool compose = true )
{
return TryResolve ( type , resolveName , null , out result , compose ) ;
}
public bool TryResolve < T > ( out T result , bool compose = true )
{
object instance ;
if ( TryResolve ( typeof ( T ) , string . Empty , null , out instance , compose ) )
{
result = ( T ) instance ;
return true ;
}
result = default ( T ) ;
return false ;
}
public bool TryResolve < T > ( object [ ] args , out T result , bool compose = true )
{
object instance ;
if ( TryResolve ( typeof ( T ) , string . Empty , args , out instance , compose ) )
{
result = ( T ) instance ;
return true ;
}
result = default ( T ) ;
return false ;
}
public bool TryResolve < T > ( string resolveName , out T result , bool compose = true )
{
object instance ;
if ( TryResolve ( typeof ( T ) , resolveName , null , out instance , compose ) )
{
result = ( T ) instance ;
return true ;
}
result = default ( T ) ;
return false ;
}
public bool TryResolve < T > ( string resolveName , object [ ] args , out T result , bool compose = true )
{
object instance ;
if ( TryResolve ( typeof ( T ) , resolveName , args , out instance , compose ) )
{
result = ( T ) instance ;
return true ;
}
result = default ( T ) ;
return false ;
}
public bool TryResolve ( Type type , string resolveName , object [ ] args , out object result , bool compose = true )
{
// Detect instance type
var resolve = GetResolvedType ( type , resolveName ) ;
if ( null = = resolve . Item1 )
{
result = null ;
return false ;
}
try
{
if ( resolve . Item2 )
{
result = MakeGenericResolving ( resolve . Item1 , type , args , compose ) ;
}
else
{
result = MakeResolving ( resolve . Item1 , args , compose ) ;
}
return true ;
}
catch ( Exception ex )
{
Log . SystemWarning (
$"Can't create type '{type.FullName}' instance for resolve dependency with contract type '{type.FullName}' and dependency name '{resolveName}'" , ex ) ;
}
result = null ;
return false ;
}
# endregion
#region Composition
/// <summary>
/// Filling in the fields and properties of an object with auto-set values flagged from the container parameters
/// </summary>
private void FillParametrizedFieldsAndProperties ( object instance )
{
foreach ( var property in instance . GetType ( ) . GetProperties ( BindingFlags . Instance | BindingFlags . NonPublic | BindingFlags . Public | BindingFlags . FlattenHierarchy ) )
{
var attr = property . GetCustomAttribute < ParameterAttribute > ( ) ;
if ( attr ! = null )
{
var parameterType = attr . Type ? ? property . PropertyType ;
var parameterName = attr . Name ? ? property . Name ;
property . SetValue ( instance , this . Get ( parameterType , parameterName ) ) ;
}
}
foreach ( var field in instance . GetType ( ) . GetFields ( BindingFlags . Instance | BindingFlags . NonPublic | BindingFlags . Public | BindingFlags . FlattenHierarchy ) )
{
var attr = field . GetCustomAttribute < ParameterAttribute > ( ) ;
if ( attr ! = null )
{
var parameterType = attr . Type ? ? field . FieldType ;
var parameterName = string . IsNullOrWhiteSpace ( attr . Name ) ? field . Name : attr . Name ;
field . SetValue ( instance , this . Get ( parameterType , parameterName ) ) ;
}
}
}
private void ComposeParts ( object instance )
{
var resolve_properties = CollectResolvingProperties ( instance . GetType ( ) ) ;
var resolve_fields = CollectResolvingFields ( instance . GetType ( ) ) ;
foreach ( var p in resolve_properties )
{
var resolve_instance = MakeInstanceBy ( p . PropertyType ,
p . GetCustomAttribute < ResolveAttribute > ( ) ) ;
p . SetValue ( instance , resolve_instance ) ;
}
foreach ( var f in resolve_fields )
{
var resolve_instance = MakeInstanceBy ( f . FieldType ,
f . GetCustomAttribute < ResolveAttribute > ( ) ) ;
f . SetValue ( instance , resolve_instance ) ;
}
FillParametrizedFieldsAndProperties ( instance ) ;
}
private void RecursiveCompose ( object instance , HashSet < object > set )
{
foreach ( var f in
instance . GetType ( ) . GetFields ( BindingFlags . Public |
BindingFlags . NonPublic |
BindingFlags . Instance ) )
{
if ( f . FieldType . IsClass | | f . FieldType . IsInterface )
{
var next = f . GetValue ( instance ) ;
if ( null ! = next )
{
if ( set . Add ( next ) )
{
RecursiveCompose ( next , set ) ;
}
}
}
}
ComposeParts ( instance ) ;
}
public void Compose ( object instance , bool recursive = true )
{
if ( recursive )
{
RecursiveCompose ( instance , new HashSet < object > ( ) ) ;
}
else
{
ComposeParts ( instance ) ;
}
}
public bool TryCompose ( object instanse , bool recursive = true )
{
try
{
Compose ( instanse , recursive ) ;
return true ;
}
catch ( Exception ex )
{
Log . SystemError ( ex , $"[Container] TryCompose error. Instance: '{instanse?.GetType()?.FullName ?? string.Empty}'. Recursive: {recursive}" ) ;
}
return false ;
}
# endregion
#region IDisposable
public void Dispose ( )
{
try
{
_rwLock . EnterWriteLock ( ) ;
foreach ( var list in _resolvingMap . Values )
{
foreach ( var item in list )
{
try
{
( item . SharedInstance as IDisposable ) ? . Dispose ( ) ;
}
catch ( Exception ex )
{
Log . SystemError ( ex , $"[Container] Singletone dispose error. Instance: '{item?.GetType()?.FullName ?? string.Empty}'" ) ;
}
if ( item . GenericInstanceCachee ! = null )
{
foreach ( var gitem in item . GenericInstanceCachee . Values )
{
try
{
( gitem as IDisposable ) ? . Dispose ( ) ;
}
catch ( Exception ex )
{
Log . SystemError ( ex , $"[Container] Generic singletone dispose error. Instance: '{gitem?.GetType()?.FullName ?? string.Empty}'" ) ;
}
}
}
}
}
}
catch ( Exception ex )
{
Log . SystemError ( ex , $"[Container] Dispose error" ) ;
}
finally
{
_rwLock . ExitWriteLock ( ) ;
}
}
# endregion
#region IEverythingStorage
private readonly Lazy < IEverythingStorage > _everything =
new Lazy < IEverythingStorage > ( EverythingStorage . Create ) ;
public void Save < T > ( string key , T value )
{
_everything . Value . Add < T > ( key , value ) ;
}
public void Remove < T > ( string key )
{
_everything . Value . Remove < T > ( key ) ;
}
public bool Contains < T > ( string key )
{
return _everything . Value . ContainsKey < T > ( key ) ;
}
public bool TrySave < T > ( string key , T value )
{
return _everything . Value . TryAdd < T > ( key , value ) ;
}
public bool TryRemove < T > ( string key )
{
return _everything . Value . TryRemove < T > ( key ) ;
}
public T Get < T > ( string key )
{
return _everything . Value . Get < T > ( key ) ;
}
public object Get ( Type type , string key )
{
MethodInfo method = typeof ( IEverythingStorage ) . GetMethod ( "Get" ) ;
MethodInfo genericMethod = method . MakeGenericMethod ( type ) ;
return genericMethod . Invoke ( _everything . Value , new object [ ] { key } ) ;
}
public void SaveOrUpdate < T > ( string key , T value )
{
_everything . Value . AddOrUpdate < T > ( key , value ) ;
}
public T GetOrDefault < T > ( string key )
{
if ( _everything . Value . ContainsKey < T > ( key ) )
return _everything . Value . Get < T > ( key ) ;
return default ( T ) ;
}
public T GetOrDefault < T > ( string key , T defaultValue )
{
if ( _everything . Value . ContainsKey < T > ( key ) )
return _everything . Value . Get < T > ( key ) ;
return defaultValue ;
}
# endregion
}
}