MonodroidStockPortfolio/MonoStockPortfolio/Framework/TinyIoC.cs
2011-01-02 17:10:27 -05:00

2887 lines
126 KiB
C#

//===============================================================================
// 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<TKey, TValue> : IDisposable
{
private readonly object _Padlock = new object();
private readonly Dictionary<TKey, TValue> _Dictionary = new Dictionary<TKey, TValue>();
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<TKey> 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
{
/// <summary>
/// Gets a generic method from a type given the method name, binding flags, generic types and parameter types
/// </summary>
/// <param name="sourceType">Source type</param>
/// <param name="bindingFlags">Binding flags</param>
/// <param name="methodName">Name of the method</param>
/// <param name="genericTypes">Generic types to use to make the method generic</param>
/// <param name="parameterTypes">Method parameters</param>
/// <returns>MethodInfo or null if no matches found</returns>
/// <exception cref="System.Reflection.AmbiguousMatchException"/>
/// <exception cref="System.ArgumentException"/>
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<Type> types)
: base(String.Format(ERROR_TEXT, registerType, GetTypesString(types)))
{
}
public TinyIoCAutoRegistrationException(Type registerType, IEnumerable<Type> types, Exception innerException)
: base(String.Format(ERROR_TEXT, registerType, GetTypesString(types)), innerException)
{
}
private static string GetTypesString(IEnumerable<Type> types)
{
var typeNames = from type in types
select type.FullName;
return string.Join(",", typeNames.ToArray());
}
}
#endregion
#region Public Setup / Settings Classes
/// <summary>
/// Name/Value pairs for specifying "user" parameters when resolving
/// </summary>
public sealed class NamedParameterOverloads : Dictionary<string, object>
{
public static NamedParameterOverloads FromIDictionary(IDictionary<string, object> data)
{
return data as NamedParameterOverloads ?? new NamedParameterOverloads(data);
}
public NamedParameterOverloads()
{
}
public NamedParameterOverloads(IDictionary<string, object> data)
: base(data)
{
}
private static readonly NamedParameterOverloads _Default = new NamedParameterOverloads();
public static NamedParameterOverloads Default
{
get
{
return _Default;
}
}
}
public enum UnregisteredResolutionActions
{
/// <summary>
/// Attempt to resolve type, even if the type isn't registered.
///
/// Registered types/options will always take precedence.
/// </summary>
AttemptResolve,
/// <summary>
/// Fail resolution if type not explicitly registered
/// </summary>
Fail,
/// <summary>
/// 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.
/// </summary>
GenericsOnly
}
public enum NamedResolutionFailureActions
{
AttemptUnnamedResolution,
Fail
}
/// <summary>
/// Resolution settings
/// </summary>
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; }
}
/// <summary>
/// Gets the default options (attempt resolution of unregistered types, fail on named resolution if name not found)
/// </summary>
public static ResolveOptions Default
{
get
{
return _Default;
}
}
/// <summary>
/// Preconfigured option for attempting resolution of unregistered types and failing on named resolution if name not found
/// </summary>
public static ResolveOptions FailNameNotFoundOnly
{
get
{
return _FailNameNotFoundOnly;
}
}
/// <summary>
/// Preconfigured option for failing on resolving unregistered types and on named resolution if name not found
/// </summary>
public static ResolveOptions FailUnregisteredAndNameNotFound
{
get
{
return _FailUnregisteredAndNameNotFound;
}
}
/// <summary>
/// Preconfigured option for failing on resolving unregistered types, but attempting unnamed resolution if name not found
/// </summary>
public static ResolveOptions FailUnregisteredOnly
{
get
{
return _FailUnregisteredOnly;
}
}
}
#endregion
public sealed class TinyIoCContainer : IDisposable
{
#region "Fluent" API
/// <summary>
/// Registration options for "fluent" API
/// </summary>
public sealed class RegisterOptions
{
private TinyIoCContainer _Container;
private TypeRegistration _Registration;
public RegisterOptions(TinyIoCContainer container, TypeRegistration registration)
{
_Container = container;
_Registration = registration;
}
/// <summary>
/// Make registration a singleton (single instance) if possible
/// </summary>
/// <returns>RegisterOptions</returns>
/// <exception cref="TinyIoCInstantiationTypeException"></exception>
public RegisterOptions AsSingleton()
{
var currentFactory = _Container.GetCurrentFactory(_Registration);
if (currentFactory == null)
throw new TinyIoCRegistrationException(_Registration.Type, "singleton");
return _Container.AddUpdateRegistration(_Registration, currentFactory.SingletonVariant);
}
/// <summary>
/// Make registration multi-instance if possible
/// </summary>
/// <returns>RegisterOptions</returns>
/// <exception cref="TinyIoCInstantiationTypeException"></exception>
public RegisterOptions AsMultiInstance()
{
var currentFactory = _Container.GetCurrentFactory(_Registration);
if (currentFactory == null)
throw new TinyIoCRegistrationException(_Registration.Type, "multi-instance");
return _Container.AddUpdateRegistration(_Registration, currentFactory.MultiInstanceVariant);
}
/// <summary>
/// Make registration hold a weak reference if possible
/// </summary>
/// <returns>RegisterOptions</returns>
/// <exception cref="TinyIoCInstantiationTypeException"></exception>
public RegisterOptions WithWeakReference()
{
var currentFactory = _Container.GetCurrentFactory(_Registration);
if (currentFactory == null)
throw new TinyIoCRegistrationException(_Registration.Type, "weak reference");
return _Container.AddUpdateRegistration(_Registration, currentFactory.WeakReferenceVariant);
}
/// <summary>
/// Make registration hold a strong reference if possible
/// </summary>
/// <returns>RegisterOptions</returns>
/// <exception cref="TinyIoCInstantiationTypeException"></exception>
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<RegisterType>(Expression<Func<RegisterType>> 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
}
/// <summary>
/// Registration options for "fluent" API when registering multiple implementations
/// </summary>
public sealed class MultiRegisterOptions
{
private IEnumerable<RegisterOptions> _RegisterOptions;
/// <summary>
/// Initializes a new instance of the MultiRegisterOptions class.
/// </summary>
/// <param name="registerOptions">Registration options</param>
public MultiRegisterOptions(IEnumerable<RegisterOptions> registerOptions)
{
_RegisterOptions = registerOptions;
}
/// <summary>
/// Make registration a singleton (single instance) if possible
/// </summary>
/// <returns>RegisterOptions</returns>
/// <exception cref="TinyIoCInstantiationTypeException"></exception>
public MultiRegisterOptions AsSingleton()
{
_RegisterOptions = ExecuteOnAllRegisterOptions(ro => ro.AsSingleton());
return this;
}
/// <summary>
/// Make registration multi-instance if possible
/// </summary>
/// <returns>MultiRegisterOptions</returns>
/// <exception cref="TinyIoCInstantiationTypeException"></exception>
public MultiRegisterOptions AsMultiInstance()
{
_RegisterOptions = ExecuteOnAllRegisterOptions(ro => ro.AsMultiInstance());
return this;
}
private IEnumerable<RegisterOptions> ExecuteOnAllRegisterOptions(Func<RegisterOptions, RegisterOptions> action)
{
var newRegisterOptions = new List<RegisterOptions>();
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
/// <summary>
/// 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.
/// </summary>
public void AutoRegister()
{
#if APPDOMAIN_GETASSEMBLIES
AutoRegisterInternal(AppDomain.CurrentDomain.GetAssemblies().Where(a => !IsIgnoredAssembly(a)), true);
#else
AutoRegisterInternal(new Assembly[] {this.GetType().Assembly}, true);
#endif
}
/// <summary>
/// Attempt to automatically register all non-generic classes and interfaces in the current app domain.
/// </summary>
/// <param name="ignoreDuplicateImplementations">Whether to ignore duplicate implementations of an interface/base class. False=throw an exception</param>
/// <exception cref="TinyIoCAutoRegistrationException"/>
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
}
/// <summary>
/// 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.
/// </summary>
/// <param name="assembly">Assembly to process</param>
public void AutoRegister(Assembly assembly)
{
AutoRegisterInternal(new Assembly[] { assembly }, true);
}
/// <summary>
/// Attempt to automatically register all non-generic classes and interfaces in the specified assembly
/// </summary>
/// <param name="assembly">Assembly to process</param>
/// <param name="ignoreDuplicateImplementations">Whether to ignore duplicate implementations of an interface/base class. False=throw an exception</param>
/// <exception cref="TinyIoCAutoRegistrationException"/>
public void AutoRegister(Assembly assembly, bool ignoreDuplicateImplementations)
{
AutoRegisterInternal(new Assembly[] { assembly }, ignoreDuplicateImplementations);
}
/// <summary>
/// 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.
/// </summary>
/// <param name="assemblies">Assemblies to process</param>
public void AutoRegister(IEnumerable<Assembly> assemblies)
{
AutoRegisterInternal(assemblies, true);
}
/// <summary>
/// Attempt to automatically register all non-generic classes and interfaces in the specified assemblies
/// </summary>
/// <param name="assemblies">Assemblies to process</param>
/// <param name="ignoreDuplicateImplementations">Whether to ignore duplicate implementations of an interface/base class. False=throw an exception</param>
/// <exception cref="TinyIoCAutoRegistrationException"/>
public void AutoRegister(IEnumerable<Assembly> assemblies, bool ignoreDuplicateImplementations)
{
AutoRegisterInternal(assemblies, ignoreDuplicateImplementations);
}
/// <summary>
/// Creates/replaces a container class registration with default options.
/// </summary>
/// <param name="registerImplementation">Type to register</param>
/// <returns>RegisterOptions for fluent API</returns>
public RegisterOptions Register(Type registerImplementation)
{
return ExecuteGenericRegister(new Type[] { registerImplementation }, new Type[] { }, null);
}
/// <summary>
/// Creates/replaces a named container class registration with default options.
/// </summary>
/// <param name="registerImplementation">Type to register</param>
/// <param name="name">Name of registration</param>
/// <returns>RegisterOptions for fluent API</returns>
public RegisterOptions Register(Type registerImplementation, string name)
{
return ExecuteGenericRegister(new Type[] { registerImplementation }, new Type[] { typeof(string) }, new object[] { name });
}
/// <summary>
/// Creates/replaces a container class registration with a given implementation and default options.
/// </summary>
/// <param name="registerType">Type to register</param>
/// <param name="registerImplementation">Type to instantiate that implements RegisterType</param>
/// <returns>RegisterOptions for fluent API</returns>
public RegisterOptions Register(Type registerType, Type registerImplementation)
{
return ExecuteGenericRegister(new Type[] { registerType, registerImplementation }, new Type[] { }, null);
}
/// <summary>
/// Creates/replaces a named container class registration with a given implementation and default options.
/// </summary>
/// <param name="registerType">Type to register</param>
/// <param name="registerImplementation">Type to instantiate that implements RegisterType</param>
/// <param name="name">Name of registration</param>
/// <returns>RegisterOptions for fluent API</returns>
public RegisterOptions Register(Type registerType, Type registerImplementation, string name)
{
return ExecuteGenericRegister(new Type[] { registerType, registerImplementation }, new Type[] { typeof(string) }, new object[] { name });
}
/// <summary>
/// Creates/replaces a container class registration with a specific, strong referenced, instance.
/// </summary>
/// <param name="registerImplementation">Type to register</param>
/// <param name="instance">Instance of RegisterType to register</param>
/// <returns>RegisterOptions for fluent API</returns>
public RegisterOptions Register(Type registerImplementation, object instance)
{
return ExecuteGenericRegister(new Type[] { registerImplementation }, new Type[] { registerImplementation }, new object[] { instance });
}
/// <summary>
/// Creates/replaces a named container class registration with a specific, strong referenced, instance.
/// </summary>
/// <param name="registerImplementation">Type to register</param>
/// <param name="instance">Instance of RegisterType to register</param>
/// <param name="name">Name of registration</param>
/// <returns>RegisterOptions for fluent API</returns>
public RegisterOptions Register(Type registerImplementation, object instance, string name)
{
return ExecuteGenericRegister(new Type[] { registerImplementation }, new Type[] { registerImplementation, typeof(string) }, new object[] { instance, name });
}
/// <summary>
/// Creates/replaces a container class registration with a specific, strong referenced, instance.
/// </summary>
/// <param name="registerType">Type to register</param>
/// <param name="registerImplementation">Type of instance to register that implements RegisterType</param>
/// <param name="instance">Instance of RegisterImplementation to register</param>
/// <returns>RegisterOptions for fluent API</returns>
public RegisterOptions Register(Type registerType, Type implementationType, object instance)
{
return ExecuteGenericRegister(new Type[] { registerType, implementationType }, new Type[] { implementationType }, new object[] { instance });
}
/// <summary>
/// Creates/replaces a named container class registration with a specific, strong referenced, instance.
/// </summary>
/// <param name="registerType">Type to register</param>
/// <param name="registerImplementation">Type of instance to register that implements RegisterType</param>
/// <param name="instance">Instance of RegisterImplementation to register</param>
/// <param name="name">Name of registration</param>
/// <returns>RegisterOptions for fluent API</returns>
public RegisterOptions Register(Type registerType, Type implementationType, object instance, string name)
{
return ExecuteGenericRegister(new Type[] { registerType, implementationType }, new Type[] { implementationType, typeof(string) }, new object[] { instance, name });
}
/// <summary>
/// Creates/replaces a container class registration with default options.
/// </summary>
/// <typeparam name="RegisterImplementation">Type to register</typeparam>
/// <returns>RegisterOptions for fluent API</returns>
public RegisterOptions Register<RegisterType>()
where RegisterType : class
{
return RegisterInternal(typeof(RegisterType), string.Empty, GetDefaultObjectFactory<RegisterType, RegisterType>());
}
/// <summary>
/// Creates/replaces a named container class registration with default options.
/// </summary>
/// <typeparam name="RegisterImplementation">Type to register</typeparam>
/// <param name="name">Name of registration</param>
/// <returns>RegisterOptions for fluent API</returns>
public RegisterOptions Register<RegisterType>(string name)
where RegisterType : class
{
return RegisterInternal(typeof(RegisterType), name, GetDefaultObjectFactory<RegisterType, RegisterType>());
}
/// <summary>
/// Creates/replaces a container class registration with a given implementation and default options.
/// </summary>
/// <typeparam name="RegisterType">Type to register</typeparam>
/// <typeparam name="RegisterImplementation">Type to instantiate that implements RegisterType</typeparam>
/// <returns>RegisterOptions for fluent API</returns>
public RegisterOptions Register<RegisterType, RegisterImplementation>()
where RegisterType : class
where RegisterImplementation : class, RegisterType
{
return RegisterInternal(typeof(RegisterType), string.Empty, GetDefaultObjectFactory<RegisterType, RegisterImplementation>());
}
/// <summary>
/// Creates/replaces a named container class registration with a given implementation and default options.
/// </summary>
/// <typeparam name="RegisterType">Type to register</typeparam>
/// <typeparam name="RegisterImplementation">Type to instantiate that implements RegisterType</typeparam>
/// <param name="name">Name of registration</param>
/// <returns>RegisterOptions for fluent API</returns>
public RegisterOptions Register<RegisterType, RegisterImplementation>(string name)
where RegisterType : class
where RegisterImplementation : class, RegisterType
{
return RegisterInternal(typeof(RegisterType), name, GetDefaultObjectFactory<RegisterType, RegisterImplementation>());
}
/// <summary>
/// Creates/replaces a container class registration with a specific, strong referenced, instance.
/// </summary>
/// <typeparam name="RegisterImplementation">Type to register</typeparam>
/// <param name="instance">Instance of RegisterType to register</param>
/// <returns>RegisterOptions for fluent API</returns>
public RegisterOptions Register<RegisterType>(RegisterType instance)
where RegisterType : class
{
return RegisterInternal(typeof(RegisterType), string.Empty, new InstanceFactory<RegisterType, RegisterType>(instance));
}
/// <summary>
/// Creates/replaces a named container class registration with a specific, strong referenced, instance.
/// </summary>
/// <typeparam name="RegisterImplementation">Type to register</typeparam>
/// <param name="instance">Instance of RegisterType to register</param>
/// <param name="name">Name of registration</param>
/// <returns>RegisterOptions for fluent API</returns>
public RegisterOptions Register<RegisterType>(RegisterType instance, string name)
where RegisterType : class
{
return RegisterInternal(typeof(RegisterType), name, new InstanceFactory<RegisterType, RegisterType>(instance));
}
/// <summary>
/// Creates/replaces a container class registration with a specific, strong referenced, instance.
/// </summary>
/// <typeparam name="RegisterType">Type to register</typeparam>
/// <typeparam name="RegisterImplementation">Type of instance to register that implements RegisterType</typeparam>
/// <param name="instance">Instance of RegisterImplementation to register</param>
/// <returns>RegisterOptions for fluent API</returns>
public RegisterOptions Register<RegisterType, RegisterImplementation>(RegisterImplementation instance)
where RegisterType : class
where RegisterImplementation : class, RegisterType
{
return RegisterInternal(typeof(RegisterType), string.Empty, new InstanceFactory<RegisterType, RegisterImplementation>(instance));
}
/// <summary>
/// Creates/replaces a named container class registration with a specific, strong referenced, instance.
/// </summary>
/// <typeparam name="RegisterType">Type to register</typeparam>
/// <typeparam name="RegisterImplementation">Type of instance to register that implements RegisterType</typeparam>
/// <param name="instance">Instance of RegisterImplementation to register</param>
/// <param name="name">Name of registration</param>
/// <returns>RegisterOptions for fluent API</returns>
public RegisterOptions Register<RegisterType, RegisterImplementation>(RegisterImplementation instance, string name)
where RegisterType : class
where RegisterImplementation : class, RegisterType
{
return RegisterInternal(typeof(RegisterType), name, new InstanceFactory<RegisterType, RegisterImplementation>(instance));
}
/// <summary>
/// Creates/replaces a container class registration with a user specified factory
/// </summary>
/// <typeparam name="RegisterType">Type to register</typeparam>
/// <param name="factory">Factory/lambda that returns an instance of RegisterType</param>
/// <returns>RegisterOptions for fluent API</returns>
public RegisterOptions Register<RegisterType>(Func<TinyIoCContainer, NamedParameterOverloads, RegisterType> factory)
where RegisterType : class
{
return RegisterInternal(typeof(RegisterType), string.Empty, new DelegateFactory<RegisterType>(factory));
}
/// <summary>
/// Creates/replaces a named container class registration with a user specified factory
/// </summary>
/// <typeparam name="RegisterType">Type to register</typeparam>
/// <param name="factory">Factory/lambda that returns an instance of RegisterType</param>
/// <param name="name">Name of registation</param>
/// <returns>RegisterOptions for fluent API</returns>
public RegisterOptions Register<RegisterType>(Func<TinyIoCContainer, NamedParameterOverloads, RegisterType> factory, string name)
where RegisterType : class
{
return RegisterInternal(typeof(RegisterType), name, new DelegateFactory<RegisterType>(factory));
}
/// <summary>
/// Register multiple implementations of a type.
///
/// Internally this registers each implementation using the full name of the class as its registration name.
/// </summary>
/// <typeparam name="RegisterType">Type that each implementation implements</typeparam>
/// <param name="types">Types that implement RegisterType</param>
/// <returns>MultiRegisterOptions for the fluent API</returns>
public MultiRegisterOptions RegisterMultiple<RegisterType>(IEnumerable<Type> 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<RegisterOptions>();
foreach (var type in types)
{
registerOptions.Add(Register(typeof(RegisterType), type, type.FullName));
}
return new MultiRegisterOptions(registerOptions);
}
#endregion
#region Resolution
/// <summary>
/// Attempts to resolve a type using default options.
/// </summary>
/// <param name="resolveType">Type to resolve</param>
/// <returns>Instance of type</returns>
/// <exception cref="TinyIoCResolutionException">Unable to resolve the type.</exception>
public object Resolve(Type resolveType)
{
return ResolveInternal(new TypeRegistration(resolveType), NamedParameterOverloads.Default, ResolveOptions.Default);
}
/// <summary>
/// Attempts to resolve a type using specified options.
/// </summary>
/// <param name="resolveType">Type to resolve</param>
/// <param name="options">Resolution options</param>
/// <returns>Instance of type</returns>
/// <exception cref="TinyIoCResolutionException">Unable to resolve the type.</exception>
public object Resolve(Type resolveType, ResolveOptions options)
{
return ResolveInternal(new TypeRegistration(resolveType), NamedParameterOverloads.Default, options);
}
/// <summary>
/// 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.
/// </summary>
/// <param name="resolveType">Type to resolve</param>
/// <param name="name">Name of registration</param>
/// <returns>Instance of type</returns>
/// <exception cref="TinyIoCResolutionException">Unable to resolve the type.</exception>
public object Resolve(Type resolveType, string name)
{
return ResolveInternal(new TypeRegistration(resolveType, name), NamedParameterOverloads.Default, ResolveOptions.Default);
}
/// <summary>
/// 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.
/// </summary>
/// <param name="resolveType">Type to resolve</param>
/// <param name="name">Name of registration</param>
/// <param name="options">Resolution options</param>
/// <returns>Instance of type</returns>
/// <exception cref="TinyIoCResolutionException">Unable to resolve the type.</exception>
public object Resolve(Type resolveType, string name, ResolveOptions options)
{
return ResolveInternal(new TypeRegistration(resolveType, name), NamedParameterOverloads.Default, options);
}
/// <summary>
/// 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.
/// </summary>
/// <param name="resolveType">Type to resolve</param>
/// <param name="parameters">User specified constructor parameters</param>
/// <returns>Instance of type</returns>
/// <exception cref="TinyIoCResolutionException">Unable to resolve the type.</exception>
public object Resolve(Type resolveType, NamedParameterOverloads parameters)
{
return ResolveInternal(new TypeRegistration(resolveType), parameters, ResolveOptions.Default);
}
/// <summary>
/// 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.
/// </summary>
/// <param name="resolveType">Type to resolve</param>
/// <param name="parameters">User specified constructor parameters</param>
/// <param name="options">Resolution options</param>
/// <returns>Instance of type</returns>
/// <exception cref="TinyIoCResolutionException">Unable to resolve the type.</exception>
public object Resolve(Type resolveType, NamedParameterOverloads parameters, ResolveOptions options)
{
return ResolveInternal(new TypeRegistration(resolveType), parameters, options);
}
/// <summary>
/// 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.
/// </summary>
/// <param name="resolveType">Type to resolve</param>
/// <param name="parameters">User specified constructor parameters</param>
/// <param name="name">Name of registration</param>
/// <returns>Instance of type</returns>
/// <exception cref="TinyIoCResolutionException">Unable to resolve the type.</exception>
public object Resolve(Type resolveType, string name, NamedParameterOverloads parameters)
{
return ResolveInternal(new TypeRegistration(resolveType, name), parameters, ResolveOptions.Default);
}
/// <summary>
/// Attempts to resolve a named type using specified options and the supplied constructor parameters.
///
/// Parameters are used in conjunction with normal container resolution to find the most suitable constructor (if one exists).
/// All user supplied parameters must exist in at least one resolvable constructor of RegisterType or resolution will fail.
/// </summary>
/// <param name="resolveType">Type to resolve</param>
/// <param name="name">Name of registration</param>
/// <param name="parameters">User specified constructor parameters</param>
/// <param name="options">Resolution options</param>
/// <returns>Instance of type</returns>
/// <exception cref="TinyIoCResolutionException">Unable to resolve the type.</exception>
public object Resolve(Type resolveType, string name, NamedParameterOverloads parameters, ResolveOptions options)
{
return ResolveInternal(new TypeRegistration(resolveType, name), parameters, options);
}
/// <summary>
/// Attempts to resolve a type using default options.
/// </summary>
/// <typeparam name="ResolveType">Type to resolve</typeparam>
/// <returns>Instance of type</returns>
/// <exception cref="TinyIoCResolutionException">Unable to resolve the type.</exception>
public ResolveType Resolve<ResolveType>()
where ResolveType : class
{
return (ResolveType)Resolve(typeof(ResolveType));
}
/// <summary>
/// Attempts to resolve a type using specified options.
/// </summary>
/// <typeparam name="ResolveType">Type to resolve</typeparam>
/// <param name="options">Resolution options</param>
/// <returns>Instance of type</returns>
/// <exception cref="TinyIoCResolutionException">Unable to resolve the type.</exception>
public ResolveType Resolve<ResolveType>(ResolveOptions options)
where ResolveType : class
{
return (ResolveType)Resolve(typeof(ResolveType), options);
}
/// <summary>
/// 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.
/// </summary>
/// <typeparam name="ResolveType">Type to resolve</typeparam>
/// <param name="name">Name of registration</param>
/// <returns>Instance of type</returns>
/// <exception cref="TinyIoCResolutionException">Unable to resolve the type.</exception>
public ResolveType Resolve<ResolveType>(string name)
where ResolveType : class
{
return (ResolveType)Resolve(typeof(ResolveType), name);
}
/// <summary>
/// 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.
/// </summary>
/// <typeparam name="ResolveType">Type to resolve</typeparam>
/// <param name="name">Name of registration</param>
/// <param name="options">Resolution options</param>
/// <returns>Instance of type</returns>
/// <exception cref="TinyIoCResolutionException">Unable to resolve the type.</exception>
public ResolveType Resolve<ResolveType>(string name, ResolveOptions options)
where ResolveType : class
{
return (ResolveType)Resolve(typeof(ResolveType), name, options);
}
/// <summary>
/// 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.
/// </summary>
/// <typeparam name="ResolveType">Type to resolve</typeparam>
/// <param name="parameters">User specified constructor parameters</param>
/// <returns>Instance of type</returns>
/// <exception cref="TinyIoCResolutionException">Unable to resolve the type.</exception>
public ResolveType Resolve<ResolveType>(NamedParameterOverloads parameters)
where ResolveType : class
{
return (ResolveType)Resolve(typeof(ResolveType), parameters);
}
/// <summary>
/// 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.
/// </summary>
/// <typeparam name="ResolveType">Type to resolve</typeparam>
/// <param name="parameters">User specified constructor parameters</param>
/// <param name="options">Resolution options</param>
/// <returns>Instance of type</returns>
/// <exception cref="TinyIoCResolutionException">Unable to resolve the type.</exception>
public ResolveType Resolve<ResolveType>(NamedParameterOverloads parameters, ResolveOptions options)
where ResolveType : class
{
return (ResolveType)Resolve(typeof(ResolveType), parameters, options);
}
/// <summary>
/// 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.
/// </summary>
/// <typeparam name="ResolveType">Type to resolve</typeparam>
/// <param name="parameters">User specified constructor parameters</param>
/// <param name="name">Name of registration</param>
/// <returns>Instance of type</returns>
/// <exception cref="TinyIoCResolutionException">Unable to resolve the type.</exception>
public ResolveType Resolve<ResolveType>(string name, NamedParameterOverloads parameters)
where ResolveType : class
{
return (ResolveType)Resolve(typeof(ResolveType), name, parameters);
}
/// <summary>
/// Attempts to resolve a named type using specified options and the supplied constructor parameters.
///
/// Parameters are used in conjunction with normal container resolution to find the most suitable constructor (if one exists).
/// All user supplied parameters must exist in at least one resolvable constructor of RegisterType or resolution will fail.
/// </summary>
/// <typeparam name="ResolveType">Type to resolve</typeparam>
/// <param name="name">Name of registration</param>
/// <param name="parameters">User specified constructor parameters</param>
/// <param name="options">Resolution options</param>
/// <returns>Instance of type</returns>
/// <exception cref="TinyIoCResolutionException">Unable to resolve the type.</exception>
public ResolveType Resolve<ResolveType>(string name, NamedParameterOverloads parameters, ResolveOptions options)
where ResolveType : class
{
return (ResolveType)Resolve(typeof(ResolveType), name, parameters, options);
}
/// <summary>
/// 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.
/// </summary>
/// <param name="resolveType">Type to resolve</param>
/// <param name="name">Name of registration</param>
/// <returns>Bool indicating whether the type can be resolved</returns>
public bool CanResolve(Type resolveType)
{
return CanResolveInternal(new TypeRegistration(resolveType), NamedParameterOverloads.Default, ResolveOptions.Default);
}
/// <summary>
/// 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.
/// </summary>
/// <param name="resolveType">Type to resolve</param>
/// <returns>Bool indicating whether the type can be resolved</returns>
private bool CanResolve(Type resolveType, string name)
{
return CanResolveInternal(new TypeRegistration(resolveType, name), NamedParameterOverloads.Default, ResolveOptions.Default);
}
/// <summary>
/// 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.
/// </summary>
/// <param name="resolveType">Type to resolve</param>
/// <param name="name">Name of registration</param>
/// <param name="options">Resolution options</param>
/// <returns>Bool indicating whether the type can be resolved</returns>
public bool CanResolve(Type resolveType, ResolveOptions options)
{
return CanResolveInternal(new TypeRegistration(resolveType), NamedParameterOverloads.Default, options);
}
/// <summary>
/// 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.
/// </summary>
/// <param name="resolveType">Type to resolve</param>
/// <param name="name">Name of registration</param>
/// <param name="options">Resolution options</param>
/// <returns>Bool indicating whether the type can be resolved</returns>
public bool CanResolve(Type resolveType, string name, ResolveOptions options)
{
return CanResolveInternal(new TypeRegistration(resolveType, name), NamedParameterOverloads.Default, options);
}
/// <summary>
/// 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.
/// </summary>
/// <param name="resolveType">Type to resolve</param>
/// <param name="parameters">User supplied named parameter overloads</param>
/// <returns>Bool indicating whether the type can be resolved</returns>
public bool CanResolve(Type resolveType, NamedParameterOverloads parameters)
{
return CanResolveInternal(new TypeRegistration(resolveType), parameters, ResolveOptions.Default);
}
/// <summary>
/// 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.
/// </summary>
/// <param name="resolveType">Type to resolve</param>
/// <param name="name">Name of registration</param>
/// <param name="parameters">User supplied named parameter overloads</param>
/// <returns>Bool indicating whether the type can be resolved</returns>
public bool CanResolve(Type resolveType, string name, NamedParameterOverloads parameters)
{
return CanResolveInternal(new TypeRegistration(resolveType, name), parameters, ResolveOptions.Default);
}
/// <summary>
/// Attempts to predict whether a given type can be resolved with the supplied constructor parameters options.
///
/// Parameters are used in conjunction with normal container resolution to find the most suitable constructor (if one exists).
/// All user supplied parameters must exist in at least one resolvable constructor of RegisterType or resolution will fail.
///
/// Note: Resolution may still fail if user defined factory registations fail to construct objects when called.
/// </summary>
/// <param name="resolveType">Type to resolve</param>
/// <param name="parameters">User supplied named parameter overloads</param>
/// <param name="options">Resolution options</param>
/// <returns>Bool indicating whether the type can be resolved</returns>
public bool CanResolve(Type resolveType, NamedParameterOverloads parameters, ResolveOptions options)
{
return CanResolveInternal(new TypeRegistration(resolveType), parameters, options);
}
/// <summary>
/// Attempts to predict whether a given named type can be resolved with the supplied constructor parameters options.
///
/// Parameters are used in conjunction with normal container resolution to find the most suitable constructor (if one exists).
/// All user supplied parameters must exist in at least one resolvable constructor of RegisterType or resolution will fail.
///
/// Note: Resolution may still fail if user defined factory registations fail to construct objects when called.
/// </summary>
/// <param name="resolveType">Type to resolve</param>
/// <param name="name">Name of registration</param>
/// <param name="parameters">User supplied named parameter overloads</param>
/// <param name="options">Resolution options</param>
/// <returns>Bool indicating whether the type can be resolved</returns>
public bool CanResolve(Type resolveType, string name, NamedParameterOverloads parameters, ResolveOptions options)
{
return CanResolveInternal(new TypeRegistration(resolveType, name), parameters, options);
}
/// <summary>
/// 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.
/// </summary>
/// <typeparam name="ResolveType">Type to resolve</typeparam>
/// <param name="name">Name of registration</param>
/// <returns>Bool indicating whether the type can be resolved</returns>
public bool CanResolve<ResolveType>()
where ResolveType : class
{
return CanResolve(typeof(ResolveType));
}
/// <summary>
/// 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.
/// </summary>
/// <typeparam name="ResolveType">Type to resolve</typeparam>
/// <returns>Bool indicating whether the type can be resolved</returns>
public bool CanResolve<ResolveType>(string name)
where ResolveType : class
{
return CanResolve(typeof(ResolveType), name);
}
/// <summary>
/// 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.
/// </summary>
/// <typeparam name="ResolveType">Type to resolve</typeparam>
/// <param name="name">Name of registration</param>
/// <param name="options">Resolution options</param>
/// <returns>Bool indicating whether the type can be resolved</returns>
public bool CanResolve<ResolveType>(ResolveOptions options)
where ResolveType : class
{
return CanResolve(typeof(ResolveType), options);
}
/// <summary>
/// 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.
/// </summary>
/// <typeparam name="ResolveType">Type to resolve</typeparam>
/// <param name="name">Name of registration</param>
/// <param name="options">Resolution options</param>
/// <returns>Bool indicating whether the type can be resolved</returns>
public bool CanResolve<ResolveType>(string name, ResolveOptions options)
where ResolveType : class
{
return CanResolve(typeof(ResolveType), name, options);
}
/// <summary>
/// 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.
/// </summary>
/// <typeparam name="ResolveType">Type to resolve</typeparam>
/// <param name="parameters">User supplied named parameter overloads</param>
/// <returns>Bool indicating whether the type can be resolved</returns>
public bool CanResolve<ResolveType>(NamedParameterOverloads parameters)
where ResolveType : class
{
return CanResolve(typeof(ResolveType), parameters);
}
/// <summary>
/// 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.
/// </summary>
/// <typeparam name="ResolveType">Type to resolve</typeparam>
/// <param name="name">Name of registration</param>
/// <param name="parameters">User supplied named parameter overloads</param>
/// <returns>Bool indicating whether the type can be resolved</returns>
public bool CanResolve<ResolveType>(string name, NamedParameterOverloads parameters)
where ResolveType : class
{
return CanResolve(typeof(ResolveType), name, parameters);
}
/// <summary>
/// Attempts to predict whether a given type can be resolved with the supplied constructor parameters options.
///
/// Parameters are used in conjunction with normal container resolution to find the most suitable constructor (if one exists).
/// All user supplied parameters must exist in at least one resolvable constructor of RegisterType or resolution will fail.
///
/// Note: Resolution may still fail if user defined factory registations fail to construct objects when called.
/// </summary>
/// <typeparam name="ResolveType">Type to resolve</typeparam>
/// <param name="parameters">User supplied named parameter overloads</param>
/// <param name="options">Resolution options</param>
/// <returns>Bool indicating whether the type can be resolved</returns>
public bool CanResolve<ResolveType>(NamedParameterOverloads parameters, ResolveOptions options)
where ResolveType : class
{
return CanResolve(typeof(ResolveType), parameters, options);
}
/// <summary>
/// Attempts to predict whether a given named type can be resolved with the supplied constructor parameters options.
///
/// Parameters are used in conjunction with normal container resolution to find the most suitable constructor (if one exists).
/// All user supplied parameters must exist in at least one resolvable constructor of RegisterType or resolution will fail.
///
/// Note: Resolution may still fail if user defined factory registations fail to construct objects when called.
/// </summary>
/// <typeparam name="ResolveType">Type to resolve</typeparam>
/// <param name="name">Name of registration</param>
/// <param name="parameters">User supplied named parameter overloads</param>
/// <param name="options">Resolution options</param>
/// <returns>Bool indicating whether the type can be resolved</returns>
public bool CanResolve<ResolveType>(string name, NamedParameterOverloads parameters, ResolveOptions options)
where ResolveType : class
{
return CanResolve(typeof(ResolveType), name, parameters, options);
}
/// <summary>
/// Attemps to resolve a type using the default options
/// </summary>
/// <param name="ResolveType">Type to resolve</param>
/// <param name="resolvedType">Resolved type or default if resolve fails</param>
/// <returns>True if resolved sucessfully, false otherwise</returns>
public bool TryResolve(Type resolveType, out object resolvedType)
{
try
{
resolvedType = Resolve(resolveType);
return true;
}
catch (TinyIoCResolutionException)
{
resolvedType = null;
return false;
}
}
/// <summary>
/// Attemps to resolve a type using the given options
/// </summary>
/// <param name="ResolveType">Type to resolve</param>
/// <param name="options">Resolution options</param>
/// <param name="resolvedType">Resolved type or default if resolve fails</param>
/// <returns>True if resolved sucessfully, false otherwise</returns>
public bool TryResolve(Type resolveType, ResolveOptions options, out object resolvedType)
{
try
{
resolvedType = Resolve(resolveType, options);
return true;
}
catch (TinyIoCResolutionException)
{
resolvedType = null;
return false;
}
}
/// <summary>
/// Attemps to resolve a type using the default options and given name
/// </summary>
/// <param name="ResolveType">Type to resolve</param>
/// <param name="name">Name of registration</param>
/// <param name="resolvedType">Resolved type or default if resolve fails</param>
/// <returns>True if resolved sucessfully, false otherwise</returns>
public bool TryResolve(Type resolveType, string name, out object resolvedType)
{
try
{
resolvedType = Resolve(resolveType, name);
return true;
}
catch (TinyIoCResolutionException)
{
resolvedType = null;
return false;
}
}
/// <summary>
/// Attemps to resolve a type using the given options and name
/// </summary>
/// <param name="ResolveType">Type to resolve</param>
/// <param name="name">Name of registration</param>
/// <param name="options">Resolution options</param>
/// <param name="resolvedType">Resolved type or default if resolve fails</param>
/// <returns>True if resolved sucessfully, false otherwise</returns>
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;
}
}
/// <summary>
/// Attemps to resolve a type using the default options and supplied constructor parameters
/// </summary>
/// <param name="ResolveType">Type to resolve</param>
/// <param name="parameters">User specified constructor parameters</param>
/// <param name="resolvedType">Resolved type or default if resolve fails</param>
/// <returns>True if resolved sucessfully, false otherwise</returns>
public bool TryResolve(Type resolveType, NamedParameterOverloads parameters, out object resolvedType)
{
try
{
resolvedType = Resolve(resolveType, parameters);
return true;
}
catch (TinyIoCResolutionException)
{
resolvedType = null;
return false;
}
}
/// <summary>
/// Attemps to resolve a type using the default options and supplied name and constructor parameters
/// </summary>
/// <param name="ResolveType">Type to resolve</param>
/// <param name="name">Name of registration</param>
/// <param name="parameters">User specified constructor parameters</param>
/// <param name="resolvedType">Resolved type or default if resolve fails</param>
/// <returns>True if resolved sucessfully, false otherwise</returns>
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;
}
}
/// <summary>
/// Attemps to resolve a type using the supplied options and constructor parameters
/// </summary>
/// <param name="ResolveType">Type to resolve</param>
/// <param name="name">Name of registration</param>
/// <param name="parameters">User specified constructor parameters</param>
/// <param name="options">Resolution options</param>
/// <param name="resolvedType">Resolved type or default if resolve fails</param>
/// <returns>True if resolved sucessfully, false otherwise</returns>
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;
}
}
/// <summary>
/// Attemps to resolve a type using the supplied name, options and constructor parameters
/// </summary>
/// <param name="ResolveType">Type to resolve</param>
/// <param name="name">Name of registration</param>
/// <param name="parameters">User specified constructor parameters</param>
/// <param name="options">Resolution options</param>
/// <param name="resolvedType">Resolved type or default if resolve fails</param>
/// <returns>True if resolved sucessfully, false otherwise</returns>
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;
}
}
/// <summary>
/// Attemps to resolve a type using the default options
/// </summary>
/// <typeparam name="ResolveType">Type to resolve</typeparam>
/// <param name="resolvedType">Resolved type or default if resolve fails</param>
/// <returns>True if resolved sucessfully, false otherwise</returns>
public bool TryResolve<ResolveType>(out ResolveType resolvedType)
where ResolveType : class
{
try
{
resolvedType = Resolve<ResolveType>();
return true;
}
catch (TinyIoCResolutionException)
{
resolvedType = default(ResolveType);
return false;
}
}
/// <summary>
/// Attemps to resolve a type using the given options
/// </summary>
/// <typeparam name="ResolveType">Type to resolve</typeparam>
/// <param name="options">Resolution options</param>
/// <param name="resolvedType">Resolved type or default if resolve fails</param>
/// <returns>True if resolved sucessfully, false otherwise</returns>
public bool TryResolve<ResolveType>(ResolveOptions options, out ResolveType resolvedType)
where ResolveType : class
{
try
{
resolvedType = Resolve<ResolveType>(options);
return true;
}
catch (TinyIoCResolutionException)
{
resolvedType = default(ResolveType);
return false;
}
}
/// <summary>
/// Attemps to resolve a type using the default options and given name
/// </summary>
/// <typeparam name="ResolveType">Type to resolve</typeparam>
/// <param name="name">Name of registration</param>
/// <param name="resolvedType">Resolved type or default if resolve fails</param>
/// <returns>True if resolved sucessfully, false otherwise</returns>
public bool TryResolve<ResolveType>(string name, out ResolveType resolvedType)
where ResolveType : class
{
try
{
resolvedType = Resolve<ResolveType>(name);
return true;
}
catch (TinyIoCResolutionException)
{
resolvedType = default(ResolveType);
return false;
}
}
/// <summary>
/// Attemps to resolve a type using the given options and name
/// </summary>
/// <typeparam name="ResolveType">Type to resolve</typeparam>
/// <param name="name">Name of registration</param>
/// <param name="options">Resolution options</param>
/// <param name="resolvedType">Resolved type or default if resolve fails</param>
/// <returns>True if resolved sucessfully, false otherwise</returns>
public bool TryResolve<ResolveType>(string name, ResolveOptions options, out ResolveType resolvedType)
where ResolveType : class
{
try
{
resolvedType = Resolve<ResolveType>(name, options);
return true;
}
catch (TinyIoCResolutionException)
{
resolvedType = default(ResolveType);
return false;
}
}
/// <summary>
/// Attemps to resolve a type using the default options and supplied constructor parameters
/// </summary>
/// <typeparam name="ResolveType">Type to resolve</typeparam>
/// <param name="parameters">User specified constructor parameters</param>
/// <param name="resolvedType">Resolved type or default if resolve fails</param>
/// <returns>True if resolved sucessfully, false otherwise</returns>
public bool TryResolve<ResolveType>(NamedParameterOverloads parameters, out ResolveType resolvedType)
where ResolveType : class
{
try
{
resolvedType = Resolve<ResolveType>(parameters);
return true;
}
catch (TinyIoCResolutionException)
{
resolvedType = default(ResolveType);
return false;
}
}
/// <summary>
/// Attemps to resolve a type using the default options and supplied name and constructor parameters
/// </summary>
/// <typeparam name="ResolveType">Type to resolve</typeparam>
/// <param name="name">Name of registration</param>
/// <param name="parameters">User specified constructor parameters</param>
/// <param name="resolvedType">Resolved type or default if resolve fails</param>
/// <returns>True if resolved sucessfully, false otherwise</returns>
public bool TryResolve<ResolveType>(string name, NamedParameterOverloads parameters, out ResolveType resolvedType)
where ResolveType : class
{
try
{
resolvedType = Resolve<ResolveType>(name, parameters);
return true;
}
catch (TinyIoCResolutionException)
{
resolvedType = default(ResolveType);
return false;
}
}
/// <summary>
/// Attemps to resolve a type using the supplied options and constructor parameters
/// </summary>
/// <typeparam name="ResolveType">Type to resolve</typeparam>
/// <param name="name">Name of registration</param>
/// <param name="parameters">User specified constructor parameters</param>
/// <param name="options">Resolution options</param>
/// <param name="resolvedType">Resolved type or default if resolve fails</param>
/// <returns>True if resolved sucessfully, false otherwise</returns>
public bool TryResolve<ResolveType>(NamedParameterOverloads parameters, ResolveOptions options, out ResolveType resolvedType)
where ResolveType : class
{
try
{
resolvedType = Resolve<ResolveType>(parameters, options);
return true;
}
catch (TinyIoCResolutionException)
{
resolvedType = default(ResolveType);
return false;
}
}
/// <summary>
/// Attemps to resolve a type using the supplied name, options and constructor parameters
/// </summary>
/// <typeparam name="ResolveType">Type to resolve</typeparam>
/// <param name="name">Name of registration</param>
/// <param name="parameters">User specified constructor parameters</param>
/// <param name="options">Resolution options</param>
/// <param name="resolvedType">Resolved type or default if resolve fails</param>
/// <returns>True if resolved sucessfully, false otherwise</returns>
public bool TryResolve<ResolveType>(string name, NamedParameterOverloads parameters, ResolveOptions options, out ResolveType resolvedType)
where ResolveType : class
{
try
{
resolvedType = Resolve<ResolveType>(name, parameters, options);
return true;
}
catch (TinyIoCResolutionException)
{
resolvedType = default(ResolveType);
return false;
}
}
/// <summary>
/// Returns all registrations of a type
/// </summary>
/// <param name="ResolveType">Type to resolveAll</param>
/// <param name="includeUnnamed">Whether to include un-named (default) registrations</param>
/// <returns>IEnumerable</returns>
public IEnumerable<object> ResolveAll(Type resolveType, bool includeUnnamed)
{
return ResolveAllInternal(resolveType, includeUnnamed).Select(o => o);
}
/// <summary>
/// Returns all registrations of a type, both named and unnamed
/// </summary>
/// <param name="ResolveType">Type to resolveAll</param>
/// <returns>IEnumerable</returns>
public IEnumerable<object> ResolveAll(Type resolveType)
{
return ResolveAll(resolveType, false);
}
/// <summary>
/// Returns all registrations of a type
/// </summary>
/// <typeparam name="ResolveType">Type to resolveAll</typeparam>
/// <param name="includeUnnamed">Whether to include un-named (default) registrations</param>
/// <returns>IEnumerable</returns>
public IEnumerable<ResolveType> ResolveAll<ResolveType>(bool includeUnnamed)
where ResolveType : class
{
foreach (var resolvedType in ResolveAll(typeof(ResolveType), includeUnnamed))
{
yield return resolvedType as ResolveType;
}
}
/// <summary>
/// Returns all registrations of a type, both named and unnamed
/// </summary>
/// <typeparam name="ResolveType">Type to resolveAll</typeparam>
/// <param name="includeUnnamed">Whether to include un-named (default) registrations</param>
/// <returns>IEnumerable</returns>
public IEnumerable<ResolveType> ResolveAll<ResolveType>()
where ResolveType : class
{
return ResolveAll<ResolveType>(true);
}
/// <summary>
/// Attempts to resolve all public property dependencies on the given object.
/// </summary>
/// <param name="input">Object to "build up"</param>
public void BuildUp(object input)
{
BuildUpInternal(input, ResolveOptions.Default);
}
/// <summary>
/// Attempts to resolve all public property dependencies on the given object using the given resolve options.
/// </summary>
/// <param name="input">Object to "build up"</param>
/// <param name="resolveOptions">Resolve options to use</param>
public void BuildUp(object input, ResolveOptions resolveOptions)
{
BuildUpInternal(input, resolveOptions);
}
#endregion
#endregion
#region Object Factories
private abstract class ObjectFactoryBase
{
/// <summary>
/// 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.
/// </summary>
public virtual bool AssumeConstruction { get { return false; } }
/// <summary>
/// The type the factory instantiates
/// </summary>
public abstract Type CreatesType { get; }
/// <summary>
/// Constructor to use, if specified
/// </summary>
public ConstructorInfo Constructor { get; protected set; }
/// <summary>
/// Create the type
/// </summary>
/// <param name="container">Container that requested the creation</param>
/// <param name="parameters">Any user parameters passed</param>
/// <returns></returns>
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;
}
}
/// <summary>
/// IObjectFactory that creates new instances of types for each resolution
/// </summary>
/// <typeparam name="RegisterType">Registered type</typeparam>
/// <typeparam name="RegisterImplementation">Type to construct to fullful request for RegisteredType</typeparam>
private class MultiInstanceFactory<RegisterType, RegisterImplementation> : 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<RegisterType, RegisterImplementation>();
}
}
public override ObjectFactoryBase MultiInstanceVariant
{
get
{
return this;
}
}
}
/// <summary>
/// IObjectFactory that invokes a specified delegate to construct the object
/// </summary>
/// <typeparam name="RegisterType">Registered type to be constructed</typeparam>
private class DelegateFactory<RegisterType> : ObjectFactoryBase
where RegisterType : class
{
private Func<TinyIoCContainer, NamedParameterOverloads, RegisterType> _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<TinyIoCContainer, NamedParameterOverloads, RegisterType> factory)
{
if (factory == null)
throw new ArgumentNullException("factory");
_factory = factory;
}
public override ObjectFactoryBase WeakReferenceVariant
{
get
{
return new WeakDelegateFactory<RegisterType>(_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");
}
}
/// <summary>
/// IObjectFactory that invokes a specified delegate to construct the object
///
/// Holds the delegate using a weak reference
/// </summary>
/// <typeparam name="RegisterType">Registered type to be constructed</typeparam>
private class WeakDelegateFactory<RegisterType> : 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<TinyIoCContainer, NamedParameterOverloads, RegisterType>;
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<TinyIoCContainer, NamedParameterOverloads, RegisterType> factory)
{
if (factory == null)
throw new ArgumentNullException("factory");
_factory = new WeakReference(factory);
}
public override ObjectFactoryBase StrongReferenceVariant
{
get
{
var factory = _factory.Target as Func<TinyIoCContainer, NamedParameterOverloads, RegisterType>;
if (factory == null)
throw new TinyIoCWeakReferenceException(typeof(RegisterType));
return new DelegateFactory<RegisterType>(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");
}
}
/// <summary>
/// Stores an particular instance to return for a type
/// </summary>
/// <typeparam name="RegisterType">Registered type</typeparam>
/// <typeparam name="RegisterImplementation">Type of the instance</typeparam>
private class InstanceFactory<RegisterType, RegisterImplementation> : 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<RegisterType, RegisterImplementation>();
}
}
public override ObjectFactoryBase WeakReferenceVariant
{
get
{
return new WeakInstanceFactory<RegisterType, RegisterImplementation>(_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();
}
}
/// <summary>
/// Stores an particular instance to return for a type
///
/// Stores the instance with a weak reference
/// </summary>
/// <typeparam name="RegisterType">Registered type</typeparam>
/// <typeparam name="RegisterImplementation">Type of the instance</typeparam>
private class WeakInstanceFactory<RegisterType, RegisterImplementation> : 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<RegisterType, RegisterImplementation>();
}
}
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<RegisterType, RegisterImplementation>(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();
}
}
/// <summary>
/// A factory that lazy instantiates a type and always returns the same instance
/// </summary>
/// <typeparam name="RegisterType">Registered type</typeparam>
/// <typeparam name="RegisterImplementation">Type to instantiate</typeparam>
private class SingletonFactory<RegisterType, RegisterImplementation> : 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<RegisterType, RegisterImplementation>();
}
}
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()
{
}
/// <summary>
/// Lazy created Singleton instance of the container for simple scenarios
/// </summary>
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<TypeRegistration, ObjectFactoryBase> _RegisteredTypes;
#endregion
#region Constructors
public TinyIoCContainer()
{
_RegisteredTypes = new SafeDictionary<TypeRegistration, ObjectFactoryBase>();
RegisterDefaultTypes();
}
TinyIoCContainer _Parent;
private TinyIoCContainer(TinyIoCContainer parent)
: this()
{
_Parent = parent;
}
#endregion
#region Internal Methods
private readonly object _AutoRegisterLock = new object();
private void AutoRegisterInternal(IEnumerable<Assembly> 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<Func<Assembly, bool>>()
{
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<Func<Type, bool>>()
{
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<TinyIoCContainer>(this);
#if TINYMESSENGER
// Only register the TinyMessenger singleton if we are the root container
if (_Parent == null)
Register<TinyMessenger.ITinyMessengerHub, TinyMessenger.TinyMessengerHub>();
#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<RegisterType, RegisterImplementation>()
where RegisterType : class
where RegisterImplementation : class, RegisterType
{
if (typeof(RegisterType).IsInterface || typeof(RegisterType).IsAbstract)
return new SingletonFactory<RegisterType, RegisterImplementation>();
return new MultiInstanceFactory<RegisterType, RegisterImplementation>();
}
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<ResolveType>
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<string, object> as second (parameters)
if ((genericType == typeof(Func<,,>) && type.GetGenericArguments()[0] == typeof(string) && type.GetGenericArguments()[1] == typeof(IDictionary<String, object>)))
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<string, object> as second (parameters)
if ((genericType == typeof(Func<,,>) && type.GetGenericArguments()[0] == typeof(string) && type.GetGenericArguments()[1] == typeof(IDictionary<string, object>)))
{
Type returnType = genericArguments[2];
var name = Expression.Parameter(typeof(string), "name");
var parameters = Expression.Parameter(typeof(IDictionary<string, object>), "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<ResolveType> 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<object> 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
}
}