//=============================================================================== // TinyIoC // // An easy to use, hassle free, Inversion of Control Container for small projects // and beginners alike. // // http://hg.grumpydev.com/tinyioc //=============================================================================== // Copyright © Steven Robbins. All rights reserved. // THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY // OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT // LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND // FITNESS FOR A PARTICULAR PURPOSE. //=============================================================================== #region Preprocessor Directives // Uncomment this line if you want the container to automatically // register the TinyMessenger messenger/event aggregator //#define TINYMESSENGER // Preprocessor directives for enabling/disabling functionality // depending on platform features. If the platform has an appropriate // #DEFINE then these should be set automatically below. #define EXPRESSIONS // Platform supports System.Linq.Expressions #define APPDOMAIN_GETASSEMBLIES // Platform supports getting all assemblies from the AppDomain object #define UNBOUND_GENERICS_GETCONSTRUCTORS // Platform supports GetConstructors on unbound generic types // CompactFramework // By default does not support System.Linq.Expressions. // AppDomain object does not support enumerating all assemblies in the app domain. #if PocketPC || WINDOWS_PHONE #undef EXPRESSIONS #undef APPDOMAIN_GETASSEMBLIES #undef UNBOUND_GENERICS_GETCONSTRUCTORS #endif #if SILVERLIGHT #undef APPDOMAIN_GETASSEMBLIES #endif #endregion namespace TinyIoC { using System; using System.Collections.Generic; using System.Linq; using System.Reflection; #if EXPRESSIONS using System.Linq.Expressions; #endif #region SafeDictionary public class SafeDictionary : IDisposable { private readonly object _Padlock = new object(); private readonly Dictionary _Dictionary = new Dictionary(); public TValue this[TKey key] { set { lock (_Padlock) { TValue current; if (_Dictionary.TryGetValue(key, out current)) { var disposable = current as IDisposable; if (disposable != null) disposable.Dispose(); } _Dictionary[key] = value; } } } public bool TryGetValue(TKey key, out TValue value) { lock (_Padlock) { return _Dictionary.TryGetValue(key, out value); } } public bool Remove(TKey key) { lock (_Padlock) { return _Dictionary.Remove(key); } } public void Clear() { lock (_Padlock) { _Dictionary.Clear(); } } public IEnumerable Keys { get { return _Dictionary.Keys; } } #region IDisposable Members public void Dispose() { lock (_Padlock) { var disposableItems = from item in _Dictionary.Values where item is IDisposable select item as IDisposable; foreach (var item in disposableItems) { item.Dispose(); } } GC.SuppressFinalize(this); } #endregion } #endregion #region Extensions public static class TypeExtensions { /// /// Gets a generic method from a type given the method name, binding flags, generic types and parameter types /// /// Source type /// Binding flags /// Name of the method /// Generic types to use to make the method generic /// Method parameters /// MethodInfo or null if no matches found /// /// public static MethodInfo GetGenericMethod(this Type sourceType, System.Reflection.BindingFlags bindingFlags, string methodName, Type[] genericTypes, Type[] parameterTypes) { var methods = sourceType.GetMethods(bindingFlags) .Where(mi => string.Equals(methodName, mi.Name, StringComparison.InvariantCulture)) .Where(mi => mi.ContainsGenericParameters) .Where(mi => mi.GetGenericArguments().Length == genericTypes.Length) .Where(mi => mi.GetParameters().Length == parameterTypes.Length) .Select(mi => mi.MakeGenericMethod(genericTypes)) .Where(mi => mi.GetParameters().Select(pi => pi.ParameterType).SequenceEqual(parameterTypes)) .ToList(); if (methods.Count > 1) throw new AmbiguousMatchException(); var method = methods.FirstOrDefault(); return method; } } #endregion #region TinyIoC Exception Types public class TinyIoCResolutionException : Exception { private const string ERROR_TEXT = "Unable to resolve type: {0}"; public TinyIoCResolutionException(Type type) : base(String.Format(ERROR_TEXT, type.FullName)) { } public TinyIoCResolutionException(Type type, Exception innerException) : base(String.Format(ERROR_TEXT, type.FullName), innerException) { } } public class TinyIoCRegistrationTypeException : Exception { private const string REGISTER_ERROR_TEXT = "Cannot register type {0} - abstract classes or interfaces are not valid implementation types for {1}."; public TinyIoCRegistrationTypeException(Type type, string factory) : base(String.Format(REGISTER_ERROR_TEXT, type.FullName, factory)) { } public TinyIoCRegistrationTypeException(Type type, string factory, Exception innerException) : base(String.Format(REGISTER_ERROR_TEXT, type.FullName, factory), innerException) { } } public class TinyIoCRegistrationException : Exception { private const string CONVERT_ERROR_TEXT = "Cannot convert current registration of {0} to {1}"; private const string GENERIC_CONSTRAINT_ERROR_TEXT = "Type {1} is not valid for a registration of type {0}"; public TinyIoCRegistrationException(Type type, string method) : base(String.Format(CONVERT_ERROR_TEXT, type.FullName, method)) { } public TinyIoCRegistrationException(Type type, string method, Exception innerException) : base(String.Format(CONVERT_ERROR_TEXT, type.FullName, method), innerException) { } public TinyIoCRegistrationException(Type registerType, Type implementationType) : base(String.Format(GENERIC_CONSTRAINT_ERROR_TEXT, registerType.FullName, implementationType.FullName)) { } public TinyIoCRegistrationException(Type registerType, Type implementationType, Exception innerException) : base(String.Format(GENERIC_CONSTRAINT_ERROR_TEXT, registerType.FullName, implementationType.FullName), innerException) { } } public class TinyIoCWeakReferenceException : Exception { private const string ERROR_TEXT = "Unable to instantiate {0} - referenced object has been reclaimed"; public TinyIoCWeakReferenceException(Type type) : base(String.Format(ERROR_TEXT, type.FullName)) { } public TinyIoCWeakReferenceException(Type type, Exception innerException) : base(String.Format(ERROR_TEXT, type.FullName), innerException) { } } public class TinyIoCConstructorResolutionException : Exception { private const string ERROR_TEXT = "Unable to resolve constructor for {0} using provided Expression."; public TinyIoCConstructorResolutionException(Type type) : base(String.Format(ERROR_TEXT, type.FullName)) { } public TinyIoCConstructorResolutionException(Type type, Exception innerException) : base(String.Format(ERROR_TEXT, type.FullName), innerException) { } public TinyIoCConstructorResolutionException(string message, Exception innerException) : base(message, innerException) { } public TinyIoCConstructorResolutionException(string message) : base(message) { } } public class TinyIoCAutoRegistrationException : Exception { private const string ERROR_TEXT = "Duplicate implementation of type {0} found ({1})."; public TinyIoCAutoRegistrationException(Type registerType, IEnumerable types) : base(String.Format(ERROR_TEXT, registerType, GetTypesString(types))) { } public TinyIoCAutoRegistrationException(Type registerType, IEnumerable types, Exception innerException) : base(String.Format(ERROR_TEXT, registerType, GetTypesString(types)), innerException) { } private static string GetTypesString(IEnumerable types) { var typeNames = from type in types select type.FullName; return string.Join(",", typeNames.ToArray()); } } #endregion #region Public Setup / Settings Classes /// /// Name/Value pairs for specifying "user" parameters when resolving /// public sealed class NamedParameterOverloads : Dictionary { public static NamedParameterOverloads FromIDictionary(IDictionary data) { return data as NamedParameterOverloads ?? new NamedParameterOverloads(data); } public NamedParameterOverloads() { } public NamedParameterOverloads(IDictionary data) : base(data) { } private static readonly NamedParameterOverloads _Default = new NamedParameterOverloads(); public static NamedParameterOverloads Default { get { return _Default; } } } public enum UnregisteredResolutionActions { /// /// Attempt to resolve type, even if the type isn't registered. /// /// Registered types/options will always take precedence. /// AttemptResolve, /// /// Fail resolution if type not explicitly registered /// Fail, /// /// Attempt to resolve unregistered type if requested type is generic /// and no registration exists for the specific generic parameters used. /// /// Registered types/options will always take precedence. /// GenericsOnly } public enum NamedResolutionFailureActions { AttemptUnnamedResolution, Fail } /// /// Resolution settings /// public sealed class ResolveOptions { private static readonly ResolveOptions _Default = new ResolveOptions(); private static readonly ResolveOptions _FailUnregisteredAndNameNotFound = new ResolveOptions() { NamedResolutionFailureAction = NamedResolutionFailureActions.Fail, UnregisteredResolutionAction = UnregisteredResolutionActions.Fail }; private static readonly ResolveOptions _FailUnregisteredOnly = new ResolveOptions() { NamedResolutionFailureAction = NamedResolutionFailureActions.AttemptUnnamedResolution, UnregisteredResolutionAction = UnregisteredResolutionActions.Fail }; private static readonly ResolveOptions _FailNameNotFoundOnly = new ResolveOptions() { NamedResolutionFailureAction = NamedResolutionFailureActions.Fail, UnregisteredResolutionAction = UnregisteredResolutionActions.AttemptResolve }; private UnregisteredResolutionActions _UnregisteredResolutionAction = UnregisteredResolutionActions.AttemptResolve; public UnregisteredResolutionActions UnregisteredResolutionAction { get { return _UnregisteredResolutionAction; } set { _UnregisteredResolutionAction = value; } } private NamedResolutionFailureActions _NamedResolutionFailureAction = NamedResolutionFailureActions.Fail; public NamedResolutionFailureActions NamedResolutionFailureAction { get { return _NamedResolutionFailureAction; } set { _NamedResolutionFailureAction = value; } } /// /// Gets the default options (attempt resolution of unregistered types, fail on named resolution if name not found) /// public static ResolveOptions Default { get { return _Default; } } /// /// Preconfigured option for attempting resolution of unregistered types and failing on named resolution if name not found /// public static ResolveOptions FailNameNotFoundOnly { get { return _FailNameNotFoundOnly; } } /// /// Preconfigured option for failing on resolving unregistered types and on named resolution if name not found /// public static ResolveOptions FailUnregisteredAndNameNotFound { get { return _FailUnregisteredAndNameNotFound; } } /// /// Preconfigured option for failing on resolving unregistered types, but attempting unnamed resolution if name not found /// public static ResolveOptions FailUnregisteredOnly { get { return _FailUnregisteredOnly; } } } #endregion public sealed class TinyIoCContainer : IDisposable { #region "Fluent" API /// /// Registration options for "fluent" API /// public sealed class RegisterOptions { private TinyIoCContainer _Container; private TypeRegistration _Registration; public RegisterOptions(TinyIoCContainer container, TypeRegistration registration) { _Container = container; _Registration = registration; } /// /// Make registration a singleton (single instance) if possible /// /// RegisterOptions /// public RegisterOptions AsSingleton() { var currentFactory = _Container.GetCurrentFactory(_Registration); if (currentFactory == null) throw new TinyIoCRegistrationException(_Registration.Type, "singleton"); return _Container.AddUpdateRegistration(_Registration, currentFactory.SingletonVariant); } /// /// Make registration multi-instance if possible /// /// RegisterOptions /// public RegisterOptions AsMultiInstance() { var currentFactory = _Container.GetCurrentFactory(_Registration); if (currentFactory == null) throw new TinyIoCRegistrationException(_Registration.Type, "multi-instance"); return _Container.AddUpdateRegistration(_Registration, currentFactory.MultiInstanceVariant); } /// /// Make registration hold a weak reference if possible /// /// RegisterOptions /// public RegisterOptions WithWeakReference() { var currentFactory = _Container.GetCurrentFactory(_Registration); if (currentFactory == null) throw new TinyIoCRegistrationException(_Registration.Type, "weak reference"); return _Container.AddUpdateRegistration(_Registration, currentFactory.WeakReferenceVariant); } /// /// Make registration hold a strong reference if possible /// /// RegisterOptions /// public RegisterOptions WithStrongReference() { var currentFactory = _Container.GetCurrentFactory(_Registration); if (currentFactory == null) throw new TinyIoCRegistrationException(_Registration.Type, "strong reference"); return _Container.AddUpdateRegistration(_Registration, currentFactory.StrongReferenceVariant); } #if EXPRESSIONS public RegisterOptions UsingConstructor(Expression> constructor) { var lambda = constructor as LambdaExpression; if (lambda == null) throw new TinyIoCConstructorResolutionException(typeof(RegisterType)); var newExpression = lambda.Body as NewExpression; if (newExpression == null) throw new TinyIoCConstructorResolutionException(typeof(RegisterType)); var constructorInfo = newExpression.Constructor; if (constructorInfo == null) throw new TinyIoCConstructorResolutionException(typeof(RegisterType)); var currentFactory = _Container.GetCurrentFactory(_Registration); if (currentFactory == null) throw new TinyIoCConstructorResolutionException(typeof(RegisterType)); currentFactory.SetConstructor(constructorInfo); return this; } #endif } /// /// Registration options for "fluent" API when registering multiple implementations /// public sealed class MultiRegisterOptions { private IEnumerable _RegisterOptions; /// /// Initializes a new instance of the MultiRegisterOptions class. /// /// Registration options public MultiRegisterOptions(IEnumerable registerOptions) { _RegisterOptions = registerOptions; } /// /// Make registration a singleton (single instance) if possible /// /// RegisterOptions /// public MultiRegisterOptions AsSingleton() { _RegisterOptions = ExecuteOnAllRegisterOptions(ro => ro.AsSingleton()); return this; } /// /// Make registration multi-instance if possible /// /// MultiRegisterOptions /// public MultiRegisterOptions AsMultiInstance() { _RegisterOptions = ExecuteOnAllRegisterOptions(ro => ro.AsMultiInstance()); return this; } private IEnumerable ExecuteOnAllRegisterOptions(Func action) { var newRegisterOptions = new List(); foreach (var registerOption in _RegisterOptions) { newRegisterOptions.Add(action(registerOption)); } return newRegisterOptions; } } #endregion #region Public API #region Child Containers public TinyIoCContainer GetChildContainer() { return new TinyIoCContainer(this); } #endregion #region Registration /// /// Attempt to automatically register all non-generic classes and interfaces in the current app domain. /// /// If more than one class implements an interface then only one implementation will be registered /// although no error will be thrown. /// public void AutoRegister() { #if APPDOMAIN_GETASSEMBLIES AutoRegisterInternal(AppDomain.CurrentDomain.GetAssemblies().Where(a => !IsIgnoredAssembly(a)), true); #else AutoRegisterInternal(new Assembly[] {this.GetType().Assembly}, true); #endif } /// /// Attempt to automatically register all non-generic classes and interfaces in the current app domain. /// /// Whether to ignore duplicate implementations of an interface/base class. False=throw an exception /// public void AutoRegister(bool ignoreDuplicateImplementations) { #if APPDOMAIN_GETASSEMBLIES AutoRegisterInternal(AppDomain.CurrentDomain.GetAssemblies().Where(a => !IsIgnoredAssembly(a)), ignoreDuplicateImplementations); #else AutoRegisterInternal(new Assembly[] { this.GetType().Assembly }, ignoreDuplicateImplementations); #endif } /// /// Attempt to automatically register all non-generic classes and interfaces in the specified assembly /// /// If more than one class implements an interface then only one implementation will be registered /// although no error will be thrown. /// /// Assembly to process public void AutoRegister(Assembly assembly) { AutoRegisterInternal(new Assembly[] { assembly }, true); } /// /// Attempt to automatically register all non-generic classes and interfaces in the specified assembly /// /// Assembly to process /// Whether to ignore duplicate implementations of an interface/base class. False=throw an exception /// public void AutoRegister(Assembly assembly, bool ignoreDuplicateImplementations) { AutoRegisterInternal(new Assembly[] { assembly }, ignoreDuplicateImplementations); } /// /// Attempt to automatically register all non-generic classes and interfaces in the specified assemblies /// /// If more than one class implements an interface then only one implementation will be registered /// although no error will be thrown. /// /// Assemblies to process public void AutoRegister(IEnumerable assemblies) { AutoRegisterInternal(assemblies, true); } /// /// Attempt to automatically register all non-generic classes and interfaces in the specified assemblies /// /// Assemblies to process /// Whether to ignore duplicate implementations of an interface/base class. False=throw an exception /// public void AutoRegister(IEnumerable assemblies, bool ignoreDuplicateImplementations) { AutoRegisterInternal(assemblies, ignoreDuplicateImplementations); } /// /// Creates/replaces a container class registration with default options. /// /// Type to register /// RegisterOptions for fluent API public RegisterOptions Register(Type registerImplementation) { return ExecuteGenericRegister(new Type[] { registerImplementation }, new Type[] { }, null); } /// /// Creates/replaces a named container class registration with default options. /// /// Type to register /// Name of registration /// RegisterOptions for fluent API public RegisterOptions Register(Type registerImplementation, string name) { return ExecuteGenericRegister(new Type[] { registerImplementation }, new Type[] { typeof(string) }, new object[] { name }); } /// /// Creates/replaces a container class registration with a given implementation and default options. /// /// Type to register /// Type to instantiate that implements RegisterType /// RegisterOptions for fluent API public RegisterOptions Register(Type registerType, Type registerImplementation) { return ExecuteGenericRegister(new Type[] { registerType, registerImplementation }, new Type[] { }, null); } /// /// Creates/replaces a named container class registration with a given implementation and default options. /// /// Type to register /// Type to instantiate that implements RegisterType /// Name of registration /// RegisterOptions for fluent API public RegisterOptions Register(Type registerType, Type registerImplementation, string name) { return ExecuteGenericRegister(new Type[] { registerType, registerImplementation }, new Type[] { typeof(string) }, new object[] { name }); } /// /// Creates/replaces a container class registration with a specific, strong referenced, instance. /// /// Type to register /// Instance of RegisterType to register /// RegisterOptions for fluent API public RegisterOptions Register(Type registerImplementation, object instance) { return ExecuteGenericRegister(new Type[] { registerImplementation }, new Type[] { registerImplementation }, new object[] { instance }); } /// /// Creates/replaces a named container class registration with a specific, strong referenced, instance. /// /// Type to register /// Instance of RegisterType to register /// Name of registration /// RegisterOptions for fluent API public RegisterOptions Register(Type registerImplementation, object instance, string name) { return ExecuteGenericRegister(new Type[] { registerImplementation }, new Type[] { registerImplementation, typeof(string) }, new object[] { instance, name }); } /// /// Creates/replaces a container class registration with a specific, strong referenced, instance. /// /// Type to register /// Type of instance to register that implements RegisterType /// Instance of RegisterImplementation to register /// RegisterOptions for fluent API public RegisterOptions Register(Type registerType, Type implementationType, object instance) { return ExecuteGenericRegister(new Type[] { registerType, implementationType }, new Type[] { implementationType }, new object[] { instance }); } /// /// Creates/replaces a named container class registration with a specific, strong referenced, instance. /// /// Type to register /// Type of instance to register that implements RegisterType /// Instance of RegisterImplementation to register /// Name of registration /// RegisterOptions for fluent API public RegisterOptions Register(Type registerType, Type implementationType, object instance, string name) { return ExecuteGenericRegister(new Type[] { registerType, implementationType }, new Type[] { implementationType, typeof(string) }, new object[] { instance, name }); } /// /// Creates/replaces a container class registration with default options. /// /// Type to register /// RegisterOptions for fluent API public RegisterOptions Register() where RegisterType : class { return RegisterInternal(typeof(RegisterType), string.Empty, GetDefaultObjectFactory()); } /// /// Creates/replaces a named container class registration with default options. /// /// Type to register /// Name of registration /// RegisterOptions for fluent API public RegisterOptions Register(string name) where RegisterType : class { return RegisterInternal(typeof(RegisterType), name, GetDefaultObjectFactory()); } /// /// Creates/replaces a container class registration with a given implementation and default options. /// /// Type to register /// Type to instantiate that implements RegisterType /// RegisterOptions for fluent API public RegisterOptions Register() where RegisterType : class where RegisterImplementation : class, RegisterType { return RegisterInternal(typeof(RegisterType), string.Empty, GetDefaultObjectFactory()); } /// /// Creates/replaces a named container class registration with a given implementation and default options. /// /// Type to register /// Type to instantiate that implements RegisterType /// Name of registration /// RegisterOptions for fluent API public RegisterOptions Register(string name) where RegisterType : class where RegisterImplementation : class, RegisterType { return RegisterInternal(typeof(RegisterType), name, GetDefaultObjectFactory()); } /// /// Creates/replaces a container class registration with a specific, strong referenced, instance. /// /// Type to register /// Instance of RegisterType to register /// RegisterOptions for fluent API public RegisterOptions Register(RegisterType instance) where RegisterType : class { return RegisterInternal(typeof(RegisterType), string.Empty, new InstanceFactory(instance)); } /// /// Creates/replaces a named container class registration with a specific, strong referenced, instance. /// /// Type to register /// Instance of RegisterType to register /// Name of registration /// RegisterOptions for fluent API public RegisterOptions Register(RegisterType instance, string name) where RegisterType : class { return RegisterInternal(typeof(RegisterType), name, new InstanceFactory(instance)); } /// /// Creates/replaces a container class registration with a specific, strong referenced, instance. /// /// Type to register /// Type of instance to register that implements RegisterType /// Instance of RegisterImplementation to register /// RegisterOptions for fluent API public RegisterOptions Register(RegisterImplementation instance) where RegisterType : class where RegisterImplementation : class, RegisterType { return RegisterInternal(typeof(RegisterType), string.Empty, new InstanceFactory(instance)); } /// /// Creates/replaces a named container class registration with a specific, strong referenced, instance. /// /// Type to register /// Type of instance to register that implements RegisterType /// Instance of RegisterImplementation to register /// Name of registration /// RegisterOptions for fluent API public RegisterOptions Register(RegisterImplementation instance, string name) where RegisterType : class where RegisterImplementation : class, RegisterType { return RegisterInternal(typeof(RegisterType), name, new InstanceFactory(instance)); } /// /// Creates/replaces a container class registration with a user specified factory /// /// Type to register /// Factory/lambda that returns an instance of RegisterType /// RegisterOptions for fluent API public RegisterOptions Register(Func factory) where RegisterType : class { return RegisterInternal(typeof(RegisterType), string.Empty, new DelegateFactory(factory)); } /// /// Creates/replaces a named container class registration with a user specified factory /// /// Type to register /// Factory/lambda that returns an instance of RegisterType /// Name of registation /// RegisterOptions for fluent API public RegisterOptions Register(Func factory, string name) where RegisterType : class { return RegisterInternal(typeof(RegisterType), name, new DelegateFactory(factory)); } /// /// Register multiple implementations of a type. /// /// Internally this registers each implementation using the full name of the class as its registration name. /// /// Type that each implementation implements /// Types that implement RegisterType /// MultiRegisterOptions for the fluent API public MultiRegisterOptions RegisterMultiple(IEnumerable types) { if (types == null) throw new ArgumentNullException("types", "types is null."); foreach (var type in types) if (!typeof(RegisterType).IsAssignableFrom(type)) throw new ArgumentException(String.Format("types: The type {0} is not assignable from {1}", typeof(RegisterType).FullName, type.FullName)); if (types.Count() != types.Distinct().Count()) throw new ArgumentException("types: The same implementation type cannot be specificed multiple times"); var registerOptions = new List(); foreach (var type in types) { registerOptions.Add(Register(typeof(RegisterType), type, type.FullName)); } return new MultiRegisterOptions(registerOptions); } #endregion #region Resolution /// /// Attempts to resolve a type using default options. /// /// Type to resolve /// Instance of type /// Unable to resolve the type. public object Resolve(Type resolveType) { return ResolveInternal(new TypeRegistration(resolveType), NamedParameterOverloads.Default, ResolveOptions.Default); } /// /// Attempts to resolve a type using specified options. /// /// Type to resolve /// Resolution options /// Instance of type /// Unable to resolve the type. public object Resolve(Type resolveType, ResolveOptions options) { return ResolveInternal(new TypeRegistration(resolveType), NamedParameterOverloads.Default, options); } /// /// Attempts to resolve a type using default options and the supplied name. /// /// 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. /// /// Type to resolve /// Name of registration /// Instance of type /// Unable to resolve the type. public object Resolve(Type resolveType, string name) { return ResolveInternal(new TypeRegistration(resolveType, name), NamedParameterOverloads.Default, ResolveOptions.Default); } /// /// Attempts to resolve a type using supplied options and name. /// /// 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. /// /// Type to resolve /// Name of registration /// Resolution options /// Instance of type /// Unable to resolve the type. public object Resolve(Type resolveType, string name, ResolveOptions options) { return ResolveInternal(new TypeRegistration(resolveType, name), NamedParameterOverloads.Default, options); } /// /// Attempts to resolve a type using default 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. /// /// Type to resolve /// User specified constructor parameters /// Instance of type /// Unable to resolve the type. public object Resolve(Type resolveType, NamedParameterOverloads parameters) { return ResolveInternal(new TypeRegistration(resolveType), parameters, ResolveOptions.Default); } /// /// Attempts to resolve a 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. /// /// Type to resolve /// User specified constructor parameters /// Resolution options /// Instance of type /// Unable to resolve the type. public object Resolve(Type resolveType, NamedParameterOverloads parameters, ResolveOptions options) { return ResolveInternal(new TypeRegistration(resolveType), parameters, options); } /// /// Attempts to resolve a type using default options and the supplied constructor parameters and name. /// /// 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. /// /// Type to resolve /// User specified constructor parameters /// Name of registration /// Instance of type /// Unable to resolve the type. public object Resolve(Type resolveType, string name, NamedParameterOverloads parameters) { return ResolveInternal(new TypeRegistration(resolveType, name), parameters, ResolveOptions.Default); } /// /// 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. /// /// Type to resolve /// Name of registration /// User specified constructor parameters /// Resolution options /// Instance of type /// Unable to resolve the type. public object Resolve(Type resolveType, string name, NamedParameterOverloads parameters, ResolveOptions options) { return ResolveInternal(new TypeRegistration(resolveType, name), parameters, options); } /// /// Attempts to resolve a type using default options. /// /// Type to resolve /// Instance of type /// Unable to resolve the type. public ResolveType Resolve() where ResolveType : class { return (ResolveType)Resolve(typeof(ResolveType)); } /// /// Attempts to resolve a type using specified options. /// /// Type to resolve /// Resolution options /// Instance of type /// Unable to resolve the type. public ResolveType Resolve(ResolveOptions options) where ResolveType : class { return (ResolveType)Resolve(typeof(ResolveType), options); } /// /// Attempts to resolve a type using default options and the supplied name. /// /// 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. /// /// Type to resolve /// Name of registration /// Instance of type /// Unable to resolve the type. public ResolveType Resolve(string name) where ResolveType : class { return (ResolveType)Resolve(typeof(ResolveType), name); } /// /// Attempts to resolve a type using supplied options and name. /// /// 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. /// /// Type to resolve /// Name of registration /// Resolution options /// Instance of type /// Unable to resolve the type. public ResolveType Resolve(string name, ResolveOptions options) where ResolveType : class { return (ResolveType)Resolve(typeof(ResolveType), name, options); } /// /// Attempts to resolve a type using default 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. /// /// Type to resolve /// User specified constructor parameters /// Instance of type /// Unable to resolve the type. public ResolveType Resolve(NamedParameterOverloads parameters) where ResolveType : class { return (ResolveType)Resolve(typeof(ResolveType), parameters); } /// /// Attempts to resolve a 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. /// /// Type to resolve /// User specified constructor parameters /// Resolution options /// Instance of type /// Unable to resolve the type. public ResolveType Resolve(NamedParameterOverloads parameters, ResolveOptions options) where ResolveType : class { return (ResolveType)Resolve(typeof(ResolveType), parameters, options); } /// /// Attempts to resolve a type using default options and the supplied constructor parameters and name. /// /// 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. /// /// Type to resolve /// User specified constructor parameters /// Name of registration /// Instance of type /// Unable to resolve the type. public ResolveType Resolve(string name, NamedParameterOverloads parameters) where ResolveType : class { return (ResolveType)Resolve(typeof(ResolveType), name, parameters); } /// /// 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. /// /// Type to resolve /// Name of registration /// User specified constructor parameters /// Resolution options /// Instance of type /// Unable to resolve the type. public ResolveType Resolve(string name, NamedParameterOverloads parameters, ResolveOptions options) where ResolveType : class { return (ResolveType)Resolve(typeof(ResolveType), name, parameters, options); } /// /// Attempts to predict whether a given type can be resolved with default options. /// /// Note: Resolution may still fail if user defined factory registations fail to construct objects when called. /// /// Type to resolve /// Name of registration /// Bool indicating whether the type can be resolved public bool CanResolve(Type resolveType) { return CanResolveInternal(new TypeRegistration(resolveType), NamedParameterOverloads.Default, ResolveOptions.Default); } /// /// Attempts to predict whether a given named type can be resolved with default options. /// /// Note: Resolution may still fail if user defined factory registations fail to construct objects when called. /// /// Type to resolve /// Bool indicating whether the type can be resolved private bool CanResolve(Type resolveType, string name) { return CanResolveInternal(new TypeRegistration(resolveType, name), NamedParameterOverloads.Default, ResolveOptions.Default); } /// /// Attempts to predict whether a given type can be resolved with the specified options. /// /// Note: Resolution may still fail if user defined factory registations fail to construct objects when called. /// /// Type to resolve /// Name of registration /// Resolution options /// Bool indicating whether the type can be resolved public bool CanResolve(Type resolveType, ResolveOptions options) { return CanResolveInternal(new TypeRegistration(resolveType), NamedParameterOverloads.Default, options); } /// /// Attempts to predict whether a given named type can be resolved with the specified options. /// /// Note: Resolution may still fail if user defined factory registations fail to construct objects when called. /// /// Type to resolve /// Name of registration /// Resolution options /// Bool indicating whether the type can be resolved public bool CanResolve(Type resolveType, string name, ResolveOptions options) { return CanResolveInternal(new TypeRegistration(resolveType, name), NamedParameterOverloads.Default, options); } /// /// Attempts to predict whether a given type can be resolved with the supplied constructor parameters and default 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 registations fail to construct objects when called. /// /// Type to resolve /// User supplied named parameter overloads /// Bool indicating whether the type can be resolved public bool CanResolve(Type resolveType, NamedParameterOverloads parameters) { return CanResolveInternal(new TypeRegistration(resolveType), parameters, ResolveOptions.Default); } /// /// Attempts to predict whether a given named type can be resolved with the supplied constructor parameters and default 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 registations fail to construct objects when called. /// /// Type to resolve /// Name of registration /// User supplied named parameter overloads /// Bool indicating whether the type can be resolved public bool CanResolve(Type resolveType, string name, NamedParameterOverloads parameters) { return CanResolveInternal(new TypeRegistration(resolveType, name), parameters, ResolveOptions.Default); } /// /// 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 registations fail to construct objects when called. /// /// Type to resolve /// User supplied named parameter overloads /// Resolution options /// Bool indicating whether the type can be resolved public bool CanResolve(Type resolveType, NamedParameterOverloads parameters, ResolveOptions options) { return CanResolveInternal(new TypeRegistration(resolveType), parameters, options); } /// /// 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 registations fail to construct objects when called. /// /// Type to resolve /// Name of registration /// User supplied named parameter overloads /// Resolution options /// Bool indicating whether the type can be resolved public bool CanResolve(Type resolveType, string name, NamedParameterOverloads parameters, ResolveOptions options) { return CanResolveInternal(new TypeRegistration(resolveType, name), parameters, options); } /// /// Attempts to predict whether a given type can be resolved with default options. /// /// Note: Resolution may still fail if user defined factory registations fail to construct objects when called. /// /// Type to resolve /// Name of registration /// Bool indicating whether the type can be resolved public bool CanResolve() where ResolveType : class { return CanResolve(typeof(ResolveType)); } /// /// Attempts to predict whether a given named type can be resolved with default options. /// /// Note: Resolution may still fail if user defined factory registations fail to construct objects when called. /// /// Type to resolve /// Bool indicating whether the type can be resolved public bool CanResolve(string name) where ResolveType : class { return CanResolve(typeof(ResolveType), name); } /// /// Attempts to predict whether a given type can be resolved with the specified options. /// /// Note: Resolution may still fail if user defined factory registations fail to construct objects when called. /// /// Type to resolve /// Name of registration /// Resolution options /// Bool indicating whether the type can be resolved public bool CanResolve(ResolveOptions options) where ResolveType : class { return CanResolve(typeof(ResolveType), options); } /// /// Attempts to predict whether a given named type can be resolved with the specified options. /// /// Note: Resolution may still fail if user defined factory registations fail to construct objects when called. /// /// Type to resolve /// Name of registration /// Resolution options /// Bool indicating whether the type can be resolved public bool CanResolve(string name, ResolveOptions options) where ResolveType : class { return CanResolve(typeof(ResolveType), name, options); } /// /// Attempts to predict whether a given type can be resolved with the supplied constructor parameters and default 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 registations fail to construct objects when called. /// /// Type to resolve /// User supplied named parameter overloads /// Bool indicating whether the type can be resolved public bool CanResolve(NamedParameterOverloads parameters) where ResolveType : class { return CanResolve(typeof(ResolveType), parameters); } /// /// Attempts to predict whether a given named type can be resolved with the supplied constructor parameters and default 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 registations fail to construct objects when called. /// /// Type to resolve /// Name of registration /// User supplied named parameter overloads /// Bool indicating whether the type can be resolved public bool CanResolve(string name, NamedParameterOverloads parameters) where ResolveType : class { return CanResolve(typeof(ResolveType), name, parameters); } /// /// 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 registations fail to construct objects when called. /// /// Type to resolve /// User supplied named parameter overloads /// Resolution options /// Bool indicating whether the type can be resolved public bool CanResolve(NamedParameterOverloads parameters, ResolveOptions options) where ResolveType : class { return CanResolve(typeof(ResolveType), parameters, options); } /// /// 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 registations fail to construct objects when called. /// /// Type to resolve /// Name of registration /// User supplied named parameter overloads /// Resolution options /// Bool indicating whether the type can be resolved public bool CanResolve(string name, NamedParameterOverloads parameters, ResolveOptions options) where ResolveType : class { return CanResolve(typeof(ResolveType), name, parameters, options); } /// /// Attemps to resolve a type using the default options /// /// Type to resolve /// Resolved type or default if resolve fails /// True if resolved sucessfully, false otherwise public bool TryResolve(Type resolveType, out object resolvedType) { try { resolvedType = Resolve(resolveType); return true; } catch (TinyIoCResolutionException) { resolvedType = null; return false; } } /// /// Attemps to resolve a type using the given options /// /// Type to resolve /// Resolution options /// Resolved type or default if resolve fails /// True if resolved sucessfully, false otherwise public bool TryResolve(Type resolveType, ResolveOptions options, out object resolvedType) { try { resolvedType = Resolve(resolveType, options); return true; } catch (TinyIoCResolutionException) { resolvedType = null; return false; } } /// /// Attemps to resolve a type using the default options and given name /// /// Type to resolve /// Name of registration /// Resolved type or default if resolve fails /// True if resolved sucessfully, false otherwise public bool TryResolve(Type resolveType, string name, out object resolvedType) { try { resolvedType = Resolve(resolveType, name); return true; } catch (TinyIoCResolutionException) { resolvedType = null; return false; } } /// /// Attemps to resolve a type using the given options and name /// /// Type to resolve /// Name of registration /// Resolution options /// Resolved type or default if resolve fails /// True if resolved sucessfully, false otherwise public bool TryResolve(Type resolveType, string name, ResolveOptions options, out object resolvedType) { try { resolvedType = Resolve(resolveType, name, options); return true; } catch (TinyIoCResolutionException) { resolvedType = null; return false; } } /// /// Attemps to resolve a type using the default options and supplied constructor parameters /// /// Type to resolve /// User specified constructor parameters /// Resolved type or default if resolve fails /// True if resolved sucessfully, false otherwise public bool TryResolve(Type resolveType, NamedParameterOverloads parameters, out object resolvedType) { try { resolvedType = Resolve(resolveType, parameters); return true; } catch (TinyIoCResolutionException) { resolvedType = null; return false; } } /// /// Attemps to resolve a type using the default options and supplied name and constructor parameters /// /// Type to resolve /// Name of registration /// User specified constructor parameters /// Resolved type or default if resolve fails /// True if resolved sucessfully, false otherwise public bool TryResolve(Type resolveType, string name, NamedParameterOverloads parameters, out object resolvedType) { try { resolvedType = Resolve(resolveType, name, parameters); return true; } catch (TinyIoCResolutionException) { resolvedType = null; return false; } } /// /// Attemps to resolve a type using the supplied options and constructor parameters /// /// Type to resolve /// Name of registration /// User specified constructor parameters /// Resolution options /// Resolved type or default if resolve fails /// True if resolved sucessfully, false otherwise public bool TryResolve(Type resolveType, NamedParameterOverloads parameters, ResolveOptions options, out object resolvedType) { try { resolvedType = Resolve(resolveType, parameters, options); return true; } catch (TinyIoCResolutionException) { resolvedType = null; return false; } } /// /// Attemps to resolve a type using the supplied name, options and constructor parameters /// /// Type to resolve /// Name of registration /// User specified constructor parameters /// Resolution options /// Resolved type or default if resolve fails /// True if resolved sucessfully, false otherwise public bool TryResolve(Type resolveType, string name, NamedParameterOverloads parameters, ResolveOptions options, out object resolvedType) { try { resolvedType = Resolve(resolveType, name, parameters, options); return true; } catch (TinyIoCResolutionException) { resolvedType = null; return false; } } /// /// Attemps to resolve a type using the default options /// /// Type to resolve /// Resolved type or default if resolve fails /// True if resolved sucessfully, false otherwise public bool TryResolve(out ResolveType resolvedType) where ResolveType : class { try { resolvedType = Resolve(); return true; } catch (TinyIoCResolutionException) { resolvedType = default(ResolveType); return false; } } /// /// Attemps to resolve a type using the given options /// /// Type to resolve /// Resolution options /// Resolved type or default if resolve fails /// True if resolved sucessfully, false otherwise public bool TryResolve(ResolveOptions options, out ResolveType resolvedType) where ResolveType : class { try { resolvedType = Resolve(options); return true; } catch (TinyIoCResolutionException) { resolvedType = default(ResolveType); return false; } } /// /// Attemps to resolve a type using the default options and given name /// /// Type to resolve /// Name of registration /// Resolved type or default if resolve fails /// True if resolved sucessfully, false otherwise public bool TryResolve(string name, out ResolveType resolvedType) where ResolveType : class { try { resolvedType = Resolve(name); return true; } catch (TinyIoCResolutionException) { resolvedType = default(ResolveType); return false; } } /// /// Attemps to resolve a type using the given options and name /// /// Type to resolve /// Name of registration /// Resolution options /// Resolved type or default if resolve fails /// True if resolved sucessfully, false otherwise public bool TryResolve(string name, ResolveOptions options, out ResolveType resolvedType) where ResolveType : class { try { resolvedType = Resolve(name, options); return true; } catch (TinyIoCResolutionException) { resolvedType = default(ResolveType); return false; } } /// /// Attemps to resolve a type using the default options and supplied constructor parameters /// /// Type to resolve /// User specified constructor parameters /// Resolved type or default if resolve fails /// True if resolved sucessfully, false otherwise public bool TryResolve(NamedParameterOverloads parameters, out ResolveType resolvedType) where ResolveType : class { try { resolvedType = Resolve(parameters); return true; } catch (TinyIoCResolutionException) { resolvedType = default(ResolveType); return false; } } /// /// Attemps to resolve a type using the default options and supplied name and constructor parameters /// /// Type to resolve /// Name of registration /// User specified constructor parameters /// Resolved type or default if resolve fails /// True if resolved sucessfully, false otherwise public bool TryResolve(string name, NamedParameterOverloads parameters, out ResolveType resolvedType) where ResolveType : class { try { resolvedType = Resolve(name, parameters); return true; } catch (TinyIoCResolutionException) { resolvedType = default(ResolveType); return false; } } /// /// Attemps to resolve a type using the supplied options and constructor parameters /// /// Type to resolve /// Name of registration /// User specified constructor parameters /// Resolution options /// Resolved type or default if resolve fails /// True if resolved sucessfully, false otherwise public bool TryResolve(NamedParameterOverloads parameters, ResolveOptions options, out ResolveType resolvedType) where ResolveType : class { try { resolvedType = Resolve(parameters, options); return true; } catch (TinyIoCResolutionException) { resolvedType = default(ResolveType); return false; } } /// /// Attemps to resolve a type using the supplied name, options and constructor parameters /// /// Type to resolve /// Name of registration /// User specified constructor parameters /// Resolution options /// Resolved type or default if resolve fails /// True if resolved sucessfully, false otherwise public bool TryResolve(string name, NamedParameterOverloads parameters, ResolveOptions options, out ResolveType resolvedType) where ResolveType : class { try { resolvedType = Resolve(name, parameters, options); return true; } catch (TinyIoCResolutionException) { resolvedType = default(ResolveType); return false; } } /// /// Returns all registrations of a type /// /// Type to resolveAll /// Whether to include un-named (default) registrations /// IEnumerable public IEnumerable ResolveAll(Type resolveType, bool includeUnnamed) { return ResolveAllInternal(resolveType, includeUnnamed).Select(o => o); } /// /// Returns all registrations of a type, both named and unnamed /// /// Type to resolveAll /// IEnumerable public IEnumerable ResolveAll(Type resolveType) { return ResolveAll(resolveType, false); } /// /// Returns all registrations of a type /// /// Type to resolveAll /// Whether to include un-named (default) registrations /// IEnumerable public IEnumerable ResolveAll(bool includeUnnamed) where ResolveType : class { foreach (var resolvedType in ResolveAll(typeof(ResolveType), includeUnnamed)) { yield return resolvedType as ResolveType; } } /// /// Returns all registrations of a type, both named and unnamed /// /// Type to resolveAll /// Whether to include un-named (default) registrations /// IEnumerable public IEnumerable ResolveAll() where ResolveType : class { return ResolveAll(true); } /// /// Attempts to resolve all public property dependencies on the given object. /// /// Object to "build up" public void BuildUp(object input) { BuildUpInternal(input, ResolveOptions.Default); } /// /// Attempts to resolve all public property dependencies on the given object using the given resolve options. /// /// Object to "build up" /// Resolve options to use public void BuildUp(object input, ResolveOptions resolveOptions) { BuildUpInternal(input, resolveOptions); } #endregion #endregion #region Object Factories private abstract class ObjectFactoryBase { /// /// Whether to assume this factory sucessfully constructs its objects /// /// Generally set to true for delegate style factories as CanResolve cannot delve /// into the delegates they contain. /// public virtual bool AssumeConstruction { get { return false; } } /// /// The type the factory instantiates /// public abstract Type CreatesType { get; } /// /// Constructor to use, if specified /// public ConstructorInfo Constructor { get; protected set; } /// /// Create the type /// /// Container that requested the creation /// Any user parameters passed /// public abstract object GetObject(TinyIoCContainer container, NamedParameterOverloads parameters, ResolveOptions options); public virtual ObjectFactoryBase SingletonVariant { get { throw new TinyIoCRegistrationException(this.GetType(), "singleton"); } } public virtual ObjectFactoryBase MultiInstanceVariant { get { throw new TinyIoCRegistrationException(this.GetType(), "multi-instance"); } } public virtual ObjectFactoryBase StrongReferenceVariant { get { throw new TinyIoCRegistrationException(this.GetType(), "strong reference"); } } public virtual ObjectFactoryBase WeakReferenceVariant { get { throw new TinyIoCRegistrationException(this.GetType(), "weak reference"); } } public virtual void SetConstructor(ConstructorInfo constructor) { Constructor = constructor; } } /// /// IObjectFactory that creates new instances of types for each resolution /// /// Registered type /// Type to construct to fullful request for RegisteredType private class MultiInstanceFactory : ObjectFactoryBase where RegisterType : class where RegisterImplementation : class, RegisterType { public override Type CreatesType { get { return typeof(RegisterImplementation); } } public MultiInstanceFactory() { if (typeof(RegisterImplementation).IsAbstract || typeof(RegisterImplementation).IsInterface) throw new TinyIoCRegistrationTypeException(typeof(RegisterImplementation), "MultiInstanceFactory"); } public override object GetObject(TinyIoCContainer container, NamedParameterOverloads parameters, ResolveOptions options) { try { return container.ConstructType(typeof(RegisterImplementation), Constructor, parameters, options); } catch (TinyIoCResolutionException ex) { throw new TinyIoCResolutionException(typeof(RegisterImplementation), ex); } } public override ObjectFactoryBase SingletonVariant { get { return new SingletonFactory(); } } public override ObjectFactoryBase MultiInstanceVariant { get { return this; } } } /// /// IObjectFactory that invokes a specified delegate to construct the object /// /// Registered type to be constructed private class DelegateFactory : ObjectFactoryBase where RegisterType : class { private Func _factory; public override bool AssumeConstruction { get { return true; } } public override Type CreatesType { get { return typeof(RegisterType); } } public override object GetObject(TinyIoCContainer container, NamedParameterOverloads parameters, ResolveOptions options) { try { return _factory.Invoke(container, parameters); } catch (Exception ex) { throw new TinyIoCResolutionException(typeof(RegisterType), ex); } } public DelegateFactory(Func factory) { if (factory == null) throw new ArgumentNullException("factory"); _factory = factory; } public override ObjectFactoryBase WeakReferenceVariant { get { return new WeakDelegateFactory(_factory); } } public override ObjectFactoryBase StrongReferenceVariant { get { return this; } } public override void SetConstructor(ConstructorInfo constructor) { throw new TinyIoCConstructorResolutionException("Constructor selection is not possible for delegate factory registrations"); } } /// /// IObjectFactory that invokes a specified delegate to construct the object /// /// Holds the delegate using a weak reference /// /// Registered type to be constructed private class WeakDelegateFactory : ObjectFactoryBase where RegisterType : class { private WeakReference _factory; public override bool AssumeConstruction { get { return true; } } public override Type CreatesType { get { return typeof(RegisterType); } } public override object GetObject(TinyIoCContainer container, NamedParameterOverloads parameters, ResolveOptions options) { var factory = _factory.Target as Func; if (factory == null) throw new TinyIoCWeakReferenceException(typeof(RegisterType)); try { return factory.Invoke(container, parameters); } catch (Exception ex) { throw new TinyIoCResolutionException(typeof(RegisterType), ex); } } public WeakDelegateFactory(Func factory) { if (factory == null) throw new ArgumentNullException("factory"); _factory = new WeakReference(factory); } public override ObjectFactoryBase StrongReferenceVariant { get { var factory = _factory.Target as Func; if (factory == null) throw new TinyIoCWeakReferenceException(typeof(RegisterType)); return new DelegateFactory(factory); } } public override ObjectFactoryBase WeakReferenceVariant { get { return this; } } public override void SetConstructor(ConstructorInfo constructor) { throw new TinyIoCConstructorResolutionException("Constructor selection is not possible for delegate factory registrations"); } } /// /// Stores an particular instance to return for a type /// /// Registered type /// Type of the instance private class InstanceFactory : ObjectFactoryBase, IDisposable where RegisterType : class where RegisterImplementation : class, RegisterType { private RegisterImplementation _instance; public override bool AssumeConstruction { get { return true; } } public InstanceFactory(RegisterImplementation instance) { _instance = instance; } public override Type CreatesType { get { return typeof(RegisterImplementation); } } public override object GetObject(TinyIoCContainer container, NamedParameterOverloads parameters, ResolveOptions options) { return _instance; } public override ObjectFactoryBase MultiInstanceVariant { get { return new MultiInstanceFactory(); } } public override ObjectFactoryBase WeakReferenceVariant { get { return new WeakInstanceFactory(_instance); } } public override ObjectFactoryBase StrongReferenceVariant { get { return this; } } public override void SetConstructor(ConstructorInfo constructor) { throw new TinyIoCConstructorResolutionException("Constructor selection is not possible for instance factory registrations"); } public void Dispose() { var disposable = _instance as IDisposable; if (disposable != null) disposable.Dispose(); } } /// /// Stores an particular instance to return for a type /// /// Stores the instance with a weak reference /// /// Registered type /// Type of the instance private class WeakInstanceFactory : ObjectFactoryBase, IDisposable where RegisterType : class where RegisterImplementation : class, RegisterType { private WeakReference _instance; public WeakInstanceFactory(RegisterImplementation instance) { _instance = new WeakReference(instance); } public override Type CreatesType { get { return typeof(RegisterImplementation); } } public override object GetObject(TinyIoCContainer container, NamedParameterOverloads parameters, ResolveOptions options) { var instance = _instance.Target as RegisterImplementation; if (instance == null) throw new TinyIoCWeakReferenceException(typeof(RegisterType)); return instance; } public override ObjectFactoryBase MultiInstanceVariant { get { return new MultiInstanceFactory(); } } public override ObjectFactoryBase WeakReferenceVariant { get { return this; } } public override ObjectFactoryBase StrongReferenceVariant { get { var instance = _instance.Target as RegisterImplementation; if (instance == null) throw new TinyIoCWeakReferenceException(typeof(RegisterType)); return new InstanceFactory(instance); } } public override void SetConstructor(ConstructorInfo constructor) { throw new TinyIoCConstructorResolutionException("Constructor selection is not possible for instance factory registrations"); } public void Dispose() { var disposable = _instance.Target as IDisposable; if (disposable != null) disposable.Dispose(); } } /// /// A factory that lazy instantiates a type and always returns the same instance /// /// Registered type /// Type to instantiate private class SingletonFactory : ObjectFactoryBase, IDisposable where RegisterType : class where RegisterImplementation : class, RegisterType { private readonly object SingletonLock = new object(); private RegisterImplementation _Current; public SingletonFactory() { if (typeof(RegisterImplementation).IsAbstract || typeof(RegisterImplementation).IsInterface) throw new TinyIoCRegistrationTypeException(typeof(RegisterImplementation), "SingletonFactory"); } public override Type CreatesType { get { return typeof(RegisterImplementation); } } public override object GetObject(TinyIoCContainer container, NamedParameterOverloads parameters, ResolveOptions options) { if (parameters.Count != 0) throw new ArgumentException("Cannot specify parameters for singleton types"); lock (SingletonLock) if (_Current == null) _Current = container.ConstructType(typeof(RegisterImplementation), Constructor, options) as RegisterImplementation; return _Current; } public override ObjectFactoryBase SingletonVariant { get { return this; } } public override ObjectFactoryBase MultiInstanceVariant { get { return new MultiInstanceFactory(); } } public void Dispose() { if (_Current != null) { var disposable = _Current as IDisposable; if (disposable != null) disposable.Dispose(); } } } #endregion #region Singleton Container private static readonly TinyIoCContainer _Current = new TinyIoCContainer(); static TinyIoCContainer() { } /// /// Lazy created Singleton instance of the container for simple scenarios /// public static TinyIoCContainer Current { get { return _Current; } } #endregion #region Type Registrations public sealed class TypeRegistration { public Type Type { get; private set; } public string Name { get; private set; } public TypeRegistration(Type type) : this(type, string.Empty) { } public TypeRegistration(Type type, string name) { Type = type; Name = name; } public override bool Equals(object obj) { var typeRegistration = obj as TypeRegistration; if (typeRegistration == null) return false; if (Type != typeRegistration.Type) return false; if (String.Compare(Name, typeRegistration.Name, StringComparison.Ordinal) != 0) return false; return true; } public override int GetHashCode() { return String.Format("{0}|{1}", Type.FullName, Name).GetHashCode(); } } private readonly SafeDictionary _RegisteredTypes; #endregion #region Constructors public TinyIoCContainer() { _RegisteredTypes = new SafeDictionary(); RegisterDefaultTypes(); } TinyIoCContainer _Parent; private TinyIoCContainer(TinyIoCContainer parent) : this() { _Parent = parent; } #endregion #region Internal Methods private readonly object _AutoRegisterLock = new object(); private void AutoRegisterInternal(IEnumerable assemblies, bool ignoreDuplicateImplementations) { lock (_AutoRegisterLock) { var defaultFactoryMethod = this.GetType().GetMethod("GetDefaultObjectFactory", BindingFlags.NonPublic | BindingFlags.Instance); var types = assemblies.SelectMany(a => a.GetTypes()).Where(t => !IsIgnoredType(t)).ToList(); var concreteTypes = from type in types where (type.IsClass == true) && (type.IsAbstract == false) && (type != this.GetType() && (type.DeclaringType != this.GetType()) && (!type.IsGenericTypeDefinition)) select type; foreach (var type in concreteTypes) { Type[] genericTypes = { type, type }; var genericDefaultFactoryMethod = defaultFactoryMethod.MakeGenericMethod(genericTypes); try { RegisterInternal(type, string.Empty, genericDefaultFactoryMethod.Invoke(this, null) as ObjectFactoryBase); } catch (MethodAccessException) { // Ignore methods we can't access - added for Silverlight } } var abstractInterfaceTypes = from type in types where ((type.IsInterface == true || type.IsAbstract == true) && (type.DeclaringType != this.GetType()) && (!type.IsGenericTypeDefinition)) select type; foreach (var type in abstractInterfaceTypes) { var implementations = from implementationType in concreteTypes where implementationType.GetInterfaces().Contains(type) || implementationType.BaseType == type select implementationType; if (!ignoreDuplicateImplementations && implementations.Count() > 1) throw new TinyIoCAutoRegistrationException(type, implementations); var firstImplementation = implementations.FirstOrDefault(); if (firstImplementation != null) { Type[] genericTypes = { type, firstImplementation }; var genericDefaultFactoryMethod = defaultFactoryMethod.MakeGenericMethod(genericTypes); try { RegisterInternal(type, string.Empty, genericDefaultFactoryMethod.Invoke(this, null) as ObjectFactoryBase); } catch (MethodAccessException) { // Ignore methods we can't access - added for Silverlight } } } } } private bool IsIgnoredAssembly(Assembly assembly) { // TODO - find a better way to remove "system" assemblies from the auto registration var ignoreChecks = new List>() { asm => asm.FullName.StartsWith("Microsoft.", StringComparison.InvariantCulture), asm => asm.FullName.StartsWith("System.", StringComparison.InvariantCulture), asm => asm.FullName.StartsWith("System,", StringComparison.InvariantCulture), asm => asm.FullName.StartsWith("CR_ExtUnitTest", StringComparison.InvariantCulture), asm => asm.FullName.StartsWith("mscorlib,", StringComparison.InvariantCulture), asm => asm.FullName.StartsWith("CR_VSTest", StringComparison.InvariantCulture), asm => asm.FullName.StartsWith("DevExpress.CodeRush", StringComparison.InvariantCulture), }; foreach (var check in ignoreChecks) { if (check(assembly)) return true; } return false; } private bool IsIgnoredType(Type type) { // TODO - find a better way to remove "system" types from the auto registration var ignoreChecks = new List>() { t => t.FullName.StartsWith("System.", StringComparison.InvariantCulture), t => t.FullName.StartsWith("Microsoft.", StringComparison.InvariantCulture), t => t.IsPrimitive, #if !UNBOUND_GENERICS_GETCONSTRUCTORS t => t.IsGenericTypeDefinition, #endif t => (t.GetConstructors(BindingFlags.Instance | BindingFlags.Public).Length == 0) && !(t.IsInterface || t.IsAbstract), }; foreach (var check in ignoreChecks) { if (check(type)) return true; } return false; } private void RegisterDefaultTypes() { Register(this); #if TINYMESSENGER // Only register the TinyMessenger singleton if we are the root container if (_Parent == null) Register(); #endif } private ObjectFactoryBase GetCurrentFactory(TypeRegistration registration) { ObjectFactoryBase current = null; _RegisteredTypes.TryGetValue(registration, out current); return current; } private RegisterOptions RegisterInternal(Type registerType, string name, ObjectFactoryBase factory) { var typeRegistration = new TypeRegistration(registerType, name); return AddUpdateRegistration(typeRegistration, factory); } private RegisterOptions AddUpdateRegistration(TypeRegistration typeRegistration, ObjectFactoryBase factory) { _RegisteredTypes[typeRegistration] = factory; return new RegisterOptions(this, typeRegistration); } private void RemoveRegistration(TypeRegistration typeRegistration) { _RegisteredTypes.Remove(typeRegistration); } private ObjectFactoryBase GetDefaultObjectFactory() where RegisterType : class where RegisterImplementation : class, RegisterType { if (typeof(RegisterType).IsInterface || typeof(RegisterType).IsAbstract) return new SingletonFactory(); return new MultiInstanceFactory(); } private bool CanResolveInternal(TypeRegistration registration, NamedParameterOverloads parameters, ResolveOptions options) { if (parameters == null) throw new ArgumentNullException("parameters"); Type checkType = registration.Type; string name = registration.Name; ObjectFactoryBase factory; if (_RegisteredTypes.TryGetValue(new TypeRegistration(checkType, name), out factory)) { if (factory.AssumeConstruction) return true; if (factory.Constructor == null) return (GetBestConstructor(factory.CreatesType, parameters, options) != null) ? true : false; else return CanConstruct(factory.Constructor, parameters, options); } // Fail if requesting named resolution and settings set to fail if unresolved // Or bubble up if we have a parent if (!String.IsNullOrEmpty(name) && options.NamedResolutionFailureAction == NamedResolutionFailureActions.Fail) return (_Parent != null) ? _Parent.CanResolveInternal(registration, parameters, options) : false; // Attemped unnamed fallback container resolution if relevant and requested if (!String.IsNullOrEmpty(name) && options.NamedResolutionFailureAction == NamedResolutionFailureActions.AttemptUnnamedResolution) { if (_RegisteredTypes.TryGetValue(new TypeRegistration(checkType), out factory)) { if (factory.AssumeConstruction) return true; return (GetBestConstructor(factory.CreatesType, parameters, options) != null) ? true : false; } } // Check if type is an automatic lazy factory request if (IsAutomaticLazyFactoryRequest(checkType)) return true; // Check if type is an IEnumerable if (IsIEnumerableRequest(registration.Type)) return true; // Attempt unregistered construction if possible and requested // If we cant', bubble if we have a parent if ((options.UnregisteredResolutionAction == UnregisteredResolutionActions.AttemptResolve) || (checkType.IsGenericType && options.UnregisteredResolutionAction == UnregisteredResolutionActions.GenericsOnly)) return (GetBestConstructor(checkType, parameters, options) != null) ? true : (_Parent != null) ? _Parent.CanResolveInternal(registration, parameters, options) : false; // Bubble resolution up the container tree if we have a parent if (_Parent != null) return _Parent.CanResolveInternal(registration, parameters, options); return false; } private bool IsIEnumerableRequest(Type type) { if (!type.IsGenericType) return false; Type genericType = type.GetGenericTypeDefinition(); if (genericType == typeof(IEnumerable<>)) return true; return false; } private bool IsAutomaticLazyFactoryRequest(Type type) { if (!type.IsGenericType) return false; Type genericType = type.GetGenericTypeDefinition(); // Just a func if (genericType == typeof(Func<>)) return true; // 2 parameter func with string as first parameter (name) if ((genericType == typeof(Func<,>) && type.GetGenericArguments()[0] == typeof(string))) return true; // 3 parameter func with string as first parameter (name) and IDictionary as second (parameters) if ((genericType == typeof(Func<,,>) && type.GetGenericArguments()[0] == typeof(string) && type.GetGenericArguments()[1] == typeof(IDictionary))) return true; return false; } private object ResolveInternal(TypeRegistration registration, NamedParameterOverloads parameters, ResolveOptions options) { ObjectFactoryBase factory; // Attempt container resolution if (_RegisteredTypes.TryGetValue(registration, out factory)) { try { return factory.GetObject(this, parameters, options); } catch (Exception ex) { throw new TinyIoCResolutionException(registration.Type, ex); } } // Fail if requesting named resolution and settings set to fail if unresolved if (!String.IsNullOrEmpty(registration.Name) && options.NamedResolutionFailureAction == NamedResolutionFailureActions.Fail) { // Bubble resolution up the container tree if we have a parent if (_Parent != null) return _Parent.ResolveInternal(registration, parameters, options); else throw new TinyIoCResolutionException(registration.Type); } // Attemped unnamed fallback container resolution if relevant and requested if (!String.IsNullOrEmpty(registration.Name) && options.NamedResolutionFailureAction == NamedResolutionFailureActions.AttemptUnnamedResolution) { if (_RegisteredTypes.TryGetValue(new TypeRegistration(registration.Type, string.Empty), out factory)) { try { return factory.GetObject(this, parameters, options); } catch (Exception ex) { throw new TinyIoCResolutionException(registration.Type, ex); } } } #if EXPRESSIONS // Attempt to construct an automatic lazy factory if possible if (IsAutomaticLazyFactoryRequest(registration.Type)) return GetLazyAutomaticFactoryRequest(registration.Type); #endif if (IsIEnumerableRequest(registration.Type)) return GetIEnumerableRequest(registration.Type); // Attempt unregistered construction if possible and requested if ((options.UnregisteredResolutionAction == UnregisteredResolutionActions.AttemptResolve) || (registration.Type.IsGenericType && options.UnregisteredResolutionAction == UnregisteredResolutionActions.GenericsOnly)) { if (!registration.Type.IsAbstract && !registration.Type.IsInterface) return ConstructType(registration.Type, parameters, options); } // Bubble resolution up the container tree if we have a parent if (_Parent != null) return _Parent.ResolveInternal(registration, parameters, options); // Unable to resolve - throw throw new TinyIoCResolutionException(registration.Type); } #if EXPRESSIONS private object GetLazyAutomaticFactoryRequest(Type type) { if (!type.IsGenericType) return null; Type genericType = type.GetGenericTypeDefinition(); Type[] genericArguments = type.GetGenericArguments(); // Just a func if (genericType == typeof(Func<>)) { Type returnType = genericArguments[0]; MethodInfo resolveMethod = typeof(TinyIoCContainer).GetMethod("Resolve", new Type[] { }); resolveMethod = resolveMethod.MakeGenericMethod(returnType); var resolveCall = Expression.Call(Expression.Constant(this), resolveMethod); var resolveLambda = Expression.Lambda(resolveCall).Compile(); return resolveLambda; } // 2 parameter func with string as first parameter (name) if ((genericType == typeof(Func<,>)) && (genericArguments[0] == typeof(string))) { Type returnType = genericArguments[1]; MethodInfo resolveMethod = typeof(TinyIoCContainer).GetMethod("Resolve", new Type[] { typeof(String) }); resolveMethod = resolveMethod.MakeGenericMethod(returnType); ParameterExpression[] resolveParameters = new ParameterExpression[] { Expression.Parameter(typeof(String), "name") }; var resolveCall = Expression.Call(Expression.Constant(this), resolveMethod, resolveParameters); var resolveLambda = Expression.Lambda(resolveCall, resolveParameters).Compile(); return resolveLambda; } // 3 parameter func with string as first parameter (name) and IDictionary as second (parameters) if ((genericType == typeof(Func<,,>) && type.GetGenericArguments()[0] == typeof(string) && type.GetGenericArguments()[1] == typeof(IDictionary))) { Type returnType = genericArguments[2]; var name = Expression.Parameter(typeof(string), "name"); var parameters = Expression.Parameter(typeof(IDictionary), "parameters"); MethodInfo resolveMethod = typeof(TinyIoCContainer).GetMethod("Resolve", new Type[] { typeof(String), typeof(NamedParameterOverloads) }); resolveMethod = resolveMethod.MakeGenericMethod(returnType); var resolveCall = Expression.Call(Expression.Constant(this), resolveMethod, name, Expression.Call(typeof(NamedParameterOverloads), "FromIDictionary", null, parameters)); var resolveLambda = Expression.Lambda(resolveCall, name, parameters).Compile(); return resolveLambda; } throw new TinyIoCResolutionException(type); } #endif private object GetIEnumerableRequest(Type type) { // Using MakeGenericMethod (slow) because we need to // cast the IEnumerable or constructing the type wil fail. // We may as well use the ResolveAll public // method to do this. var resolveAllMethod = this.GetType().GetMethod("ResolveAll", new Type[] { }); var genericResolveAllMethod = resolveAllMethod.MakeGenericMethod(type.GetGenericArguments()[0]); return genericResolveAllMethod.Invoke(this, new object[] { }); } private bool CanConstruct(ConstructorInfo ctor, NamedParameterOverloads parameters, ResolveOptions options) { if (parameters == null) throw new ArgumentNullException("parameters"); foreach (var parameter in ctor.GetParameters()) { if (string.IsNullOrEmpty(parameter.Name)) return false; var isParameterOverload = parameters.ContainsKey(parameter.Name); if (parameter.ParameterType.IsPrimitive && !isParameterOverload) return false; if (!isParameterOverload && !CanResolveInternal(new TypeRegistration(parameter.ParameterType), NamedParameterOverloads.Default, options)) return false; } return true; } private ConstructorInfo GetBestConstructor(Type type, NamedParameterOverloads parameters, ResolveOptions options) { if (parameters == null) throw new ArgumentNullException("parameters"); if (type.IsValueType) return null; // Get constructors in reverse order based on the number of parameters // i.e. be as "greedy" as possible so we satify the most amount of dependencies possible var ctors = from ctor in type.GetConstructors() orderby ctor.GetParameters().Count() descending select ctor; foreach (var ctor in ctors) { if (CanConstruct(ctor, parameters, options)) return ctor; } return null; } private object ConstructType(Type type, ResolveOptions options) { return ConstructType(type, null, NamedParameterOverloads.Default, options); } private object ConstructType(Type type, ConstructorInfo constructor, ResolveOptions options) { return ConstructType(type, constructor, NamedParameterOverloads.Default, options); } private object ConstructType(Type type, NamedParameterOverloads parameters, ResolveOptions options) { return ConstructType(type, null, parameters, options); } private object ConstructType(Type type, ConstructorInfo constructor, NamedParameterOverloads parameters, ResolveOptions options) { if (constructor == null) constructor = GetBestConstructor(type, parameters, options); if (constructor == null) throw new TinyIoCResolutionException(type); var ctorParams = constructor.GetParameters(); object[] args = new object[ctorParams.Count()]; for (int parameterIndex = 0; parameterIndex < ctorParams.Count(); parameterIndex++) { var currentParam = ctorParams[parameterIndex]; args[parameterIndex] = parameters.ContainsKey(currentParam.Name) ? parameters[currentParam.Name] : ResolveInternal(new TypeRegistration(currentParam.ParameterType), NamedParameterOverloads.Default, options); } try { return constructor.Invoke(args); } catch (Exception ex) { throw new TinyIoCResolutionException(type, ex); } } private void BuildUpInternal(object input, ResolveOptions resolveOptions) { var properties = from property in input.GetType().GetProperties() where (property.GetGetMethod() != null) && (property.GetSetMethod() != null) && !property.PropertyType.IsValueType select property; foreach (var property in properties) { if (property.GetValue(input, null) == null) { try { property.SetValue(input, ResolveInternal(new TypeRegistration(property.PropertyType), NamedParameterOverloads.Default, resolveOptions), null); } catch (TinyIoCResolutionException) { // Catch any resolution errors and ignore them } } } } private IEnumerable ResolveAllInternal(Type resolveType, bool includeUnnamed) { var registrations = _RegisteredTypes.Keys.Where(tr => tr.Type == resolveType); if (!includeUnnamed) registrations = registrations.Where(tr => tr.Name != string.Empty); foreach (var registration in registrations) { yield return ResolveInternal(registration, NamedParameterOverloads.Default, ResolveOptions.Default); } } private RegisterOptions ExecuteGenericRegister(Type[] genericParameterTypes, Type[] methodParameterTypes, object[] methodParameters) { try { var method = this.GetType().GetGenericMethod(BindingFlags.Instance | BindingFlags.Public, "Register", genericParameterTypes, methodParameterTypes); return (RegisterOptions)method.Invoke(this, methodParameters); } catch (ArgumentException ex) { var registrationType = genericParameterTypes[0]; var implementationType = genericParameterTypes[1]; if (genericParameterTypes.Length == 2) implementationType = genericParameterTypes[2]; throw new TinyIoCRegistrationException(registrationType, implementationType, ex); } } #endregion #region IDisposable Members bool disposed = false; public void Dispose() { if (!disposed) { disposed = true; _RegisteredTypes.Dispose(); GC.SuppressFinalize(this); } } #endregion } }