# HG changeset patch # User srobbins <> # Date 1270486244 -3600 # Node ID d55f4c95f2e3a014de9f1d4594352914c22629b8 # Parent 9758b42893214968c3267a8a34383d124f1ba008 Added support for CompactFramework Added Platform Tests for testing features on individual platforms. diff -r 9758b42893214968c3267a8a34383d124f1ba008 -r d55f4c95f2e3a014de9f1d4594352914c22629b8 TinyIoC.Tests/PlatformTestSuite/PlatformTests.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/TinyIoC.Tests/PlatformTestSuite/PlatformTests.cs Mon Apr 05 17:50:44 2010 +0100 @@ -0,0 +1,385 @@ +#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 +#undef EXPRESSIONS +#undef APPDOMAIN_GETASSEMBLIES +#undef UNBOUND_GENERICS_GETCONSTRUCTORS +#endif +#endregion + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace TinyIoC.Tests.PlatformTestSuite +{ + public interface ILogger + { + void WriteLine(string text); + } + + public class PlatformTests + { + #region TestClasses + public class TestClassNoInterface + { + } + + public interface ITestInterface + { + } + + public interface ITestInterface2 + { + } + + public class TestClassWithInterface : ITestInterface + { + } + + public class TestClassWithInterface2 : ITestInterface2 + { + } + + public class TestClassWithConcreteDependency + { + public TestClassNoInterface Dependency { get; set; } + + public TestClassWithConcreteDependency(TestClassNoInterface dependency) + { + Dependency = dependency; + } + + public TestClassWithConcreteDependency() + { + + } + } + + public class TestClassWithInterfaceDependency + { + public ITestInterface Dependency { get; set; } + + public TestClassWithInterfaceDependency(ITestInterface dependency) + { + Dependency = dependency; + } + } + + public class TestClassWithParameters + { + public string StringProperty { get; set; } + public int IntProperty { get; set; } + + public TestClassWithParameters(string stringProperty, int intProperty) + { + StringProperty = stringProperty; + IntProperty = intProperty; + } + } + + public class GenericClass + { + + } + + public class TestClassWithLazyFactory + { + private Func _Factory; + public TestClassNoInterface Prop1 { get; private set; } + public TestClassNoInterface Prop2 { get; private set; } + + /// + /// Initializes a new instance of the TestClassWithLazyFactory class. + /// + /// + public TestClassWithLazyFactory(Func factory) + { + _Factory = factory; + Prop1 = _Factory.Invoke(); + Prop2 = _Factory.Invoke(); + } + } + + public class TestClassWithNamedLazyFactory + { + private Func _Factory; + public TestClassNoInterface Prop1 { get; private set; } + public TestClassNoInterface Prop2 { get; private set; } + + /// + /// Initializes a new instance of the TestClassWithLazyFactory class. + /// + /// + public TestClassWithNamedLazyFactory(Func factory) + { + _Factory = factory; + Prop1 = _Factory.Invoke("Testing"); + Prop2 = _Factory.Invoke("Testing"); + } + } + + internal class TestclassWithNameAndParamsLazyFactory + { + private Func, TestClassWithParameters> _Factory; + public TestClassWithParameters Prop1 { get; private set; } + + public TestclassWithNameAndParamsLazyFactory(Func, TestClassWithParameters> factory) + { + _Factory = factory; + Prop1 = _Factory.Invoke("Testing", new Dictionary { { "stringProperty", "Testing" }, { "intProperty", 22 } }); + } + } + #endregion + + + private ILogger _Logger; + private int _TestsRun; + private int _TestsPassed; + private int _TestsFailed; + + private List> _Tests; + + public PlatformTests(ILogger logger) + { + _Logger = logger; + + _Tests = new List>() + { + AutoRegisterAppDomain, + AutoRegisterAssemblySpecified, + RegisterConcrete, + ResolveConcreteUnregisteredDefaultOptions, + ResolveConcreteRegisteredDefaultOptions, + RegisterNamedConcrete, + ResolveNamedConcrete, + RegisterInstance, + RegisterInterface, + RegisterStrongRef, + RegisterWeakRef, + RegisterFactory, +#if EXPRESSIONS + RegisterAndSpecifyConstructor, +#endif + RegisterBoundGeneric, + RegisterUnboundGeneric, +#if EXPRESSIONS + ResolveLazyFactory, + ResolveNamedLazyFactory, + ResolveNamedAndParamsLazyFactory +#endif + }; + } + + public void RunTests(out int testsRun, out int testsPassed, out int testsFailed) + { + _TestsRun = 0; + _TestsPassed = 0; + _TestsFailed = 0; + + foreach (var test in _Tests) + { + var container = GetContainer(); + try + { + _TestsRun++; + if (test.Invoke(container, _Logger)) + _TestsPassed++; + else + _TestsFailed++; + } + catch (Exception ex) + { + _TestsFailed++; + _Logger.WriteLine(String.Format("Test Failed: {0}", ex.Message)); + } + } + + testsRun = _TestsRun; + testsPassed = _TestsPassed; + testsFailed = _TestsFailed; + } + + private TinyIoC.TinyIoCContainer GetContainer() + { + return new TinyIoCContainer(); + } + + private bool AutoRegisterAppDomain(TinyIoCContainer container, ILogger logger) + { + logger.WriteLine("AutoRegisterAppDomain"); + container.AutoRegister(); + container.Resolve(); + return true; + } + + private bool AutoRegisterAssemblySpecified(TinyIoCContainer container, ILogger logger) + { + logger.WriteLine("AutoRegisterAssemblySpecified"); + container.AutoRegister(this.GetType().Assembly); + container.Resolve(); + return true; + } + + private bool RegisterConcrete(TinyIoCContainer container, ILogger logger) + { + logger.WriteLine("RegisterConcrete"); + container.Register(); + container.Resolve(); + return true; + } + + private bool ResolveConcreteUnregisteredDefaultOptions(TinyIoCContainer container, ILogger logger) + { + logger.WriteLine("ResolveConcreteUnregisteredDefaultOptions"); + var output = container.Resolve(); + + return output is TestClassNoInterface; + } + + private bool ResolveConcreteRegisteredDefaultOptions(TinyIoCContainer container, ILogger logger) + { + logger.WriteLine("ResolveConcreteRegisteredDefaultOptions"); + container.Register(); + var output = container.Resolve(); + + return output is TestClassNoInterface; + } + + private bool RegisterNamedConcrete(TinyIoCContainer container, ILogger logger) + { + logger.WriteLine("RegisterNamedConcrete"); + container.Register("Testing"); + var output = container.Resolve("Testing"); + + return output is TestClassNoInterface; + } + + private bool ResolveNamedConcrete(TinyIoCContainer container, ILogger logger) + { + logger.WriteLine("ResolveNamedConcrete"); + container.Register("Testing"); + var output = container.Resolve("Testing"); + + return output is TestClassNoInterface; + } + + private bool RegisterInstance(TinyIoCContainer container, ILogger logger) + { + logger.WriteLine("RegisterInstance"); + var obj = new TestClassNoInterface(); + container.Register(obj); + var output = container.Resolve(); + return object.ReferenceEquals(obj, output); + } + + private bool RegisterInterface(TinyIoCContainer container, ILogger logger) + { + logger.WriteLine("RegisterInterface"); + container.Register(); + var output = container.Resolve(); + return output is ITestInterface; + } + + private bool RegisterStrongRef(TinyIoCContainer container, ILogger logger) + { + logger.WriteLine("RegisterStrongRef"); + var obj = new TestClassNoInterface(); + container.Register(obj).WithStrongReference(); + var output = container.Resolve(); + + return output is TestClassNoInterface; + } + + private bool RegisterWeakRef(TinyIoCContainer container, ILogger logger) + { + logger.WriteLine("RegisterWeakRef"); + var obj = new TestClassNoInterface(); + container.Register(obj).WithWeakReference(); + var output = container.Resolve(); + + return output is TestClassNoInterface; + } + + private bool RegisterFactory(TinyIoCContainer container, ILogger logger) + { + logger.WriteLine("RegisterFactory"); + container.Register((c, p) => new TestClassNoInterface()); + var output = container.Resolve(); + + return output is TestClassNoInterface; + } + +#if EXPRESSIONS + private bool RegisterAndSpecifyConstructor(TinyIoCContainer container, ILogger logger) + { + logger.WriteLine("RegisterAndSpecifyConstructor"); + container.Register().UsingConstructor(() => new TestClassWithConcreteDependency()); + var output = container.Resolve(); + + return output is TestClassWithConcreteDependency; + } +#endif + + private bool RegisterBoundGeneric(TinyIoCContainer container, ILogger logger) + { + logger.WriteLine("RegisterBoundGeneric"); + container.Register>(); + var output = container.Resolve>(); + + return output is GenericClass; + } + + private bool RegisterUnboundGeneric(TinyIoCContainer container, ILogger logger) + { + logger.WriteLine("RegisterUnboundGeneric"); + container.Register(typeof(GenericClass<>)); + var output = container.Resolve>(new ResolveOptions(){UnregisteredResolutionAction = UnregisteredResolutionActions.GenericsOnly}); + + return output is GenericClass; + } + +#if EXPRESSIONS + private bool ResolveLazyFactory(TinyIoCContainer container, ILogger logger) + { + logger.WriteLine("ResolveLazyFactory"); + container.Register(); + container.Register(); + var output = container.Resolve(); + return (output.Prop1 != null) && (output.Prop2 != null); + } + + private bool ResolveNamedLazyFactory(TinyIoCContainer container, ILogger logger) + { + logger.WriteLine("ResolveNamedLazyFactory"); + container.Register("Testing"); + container.Register(); + var output = container.Resolve(); + return (output.Prop1 != null) && (output.Prop2 != null); + } + + private bool ResolveNamedAndParamsLazyFactory(TinyIoCContainer container, ILogger logger) + { + logger.WriteLine("ResolveNamedAndParamsLazyFactory"); + container.Register("Testing"); + container.Register(); + var output = container.Resolve(); + return (output.Prop1 != null); + } +#endif + } +} diff -r 9758b42893214968c3267a8a34383d124f1ba008 -r d55f4c95f2e3a014de9f1d4594352914c22629b8 TinyIoC.Tests/TinyIoC.Tests.csproj --- a/TinyIoC.Tests/TinyIoC.Tests.csproj Thu Apr 01 19:04:20 2010 +0100 +++ b/TinyIoC.Tests/TinyIoC.Tests.csproj Mon Apr 05 17:50:44 2010 +0100 @@ -41,6 +41,7 @@ + True diff -r 9758b42893214968c3267a8a34383d124f1ba008 -r d55f4c95f2e3a014de9f1d4594352914c22629b8 TinyIoC.Tests/TinyIoCTests.cs --- a/TinyIoC.Tests/TinyIoCTests.cs Thu Apr 01 19:04:20 2010 +0100 +++ b/TinyIoC.Tests/TinyIoCTests.cs Mon Apr 05 17:50:44 2010 +0100 @@ -1212,6 +1212,15 @@ } [TestMethod] + [ExpectedException(typeof(TinyIoCResolutionException))] + public void Resolve_NormalUnregisteredType_FailsWithUnregisteredFallbackSetToGenericsOnly() + { + var container = UtilityMethods.GetContainer(); + + var testing = container.Resolve(new ResolveOptions() { UnregisteredResolutionAction = UnregisteredResolutionActions.GenericsOnly }); + } + + [TestMethod] public void Resolve_BoundGenericTypeWithoutRegistered_ResolvesWithUnRegisteredFallbackSetToGenericsOnly() { var container = UtilityMethods.GetContainer(); diff -r 9758b42893214968c3267a8a34383d124f1ba008 -r d55f4c95f2e3a014de9f1d4594352914c22629b8 TinyIoC/TinyIoC.cs --- a/TinyIoC/TinyIoC.cs Thu Apr 01 19:04:20 2010 +0100 +++ b/TinyIoC/TinyIoC.cs Mon Apr 05 17:50:44 2010 +0100 @@ -13,16 +13,37 @@ // 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 + #undef EXPRESSIONS + #undef APPDOMAIN_GETASSEMBLIES + #undef UNBOUND_GENERICS_GETCONSTRUCTORS +#endif +#endregion + using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Reflection; +using System.Diagnostics; +#if EXPRESSIONS using System.Linq.Expressions; +#endif namespace TinyIoC { @@ -378,6 +399,7 @@ return _Container.AddUpdateRegistration(_Registration, currentFactory.StrongReferenceVariant); } +#if EXPRESSIONS public RegisterOptions UsingConstructor(Expression> constructor) { var lambda = constructor as LambdaExpression; @@ -400,6 +422,7 @@ return this; } +#endif } #endregion @@ -420,7 +443,11 @@ /// public void AutoRegister() { +#if APPDOMAIN_GETASSEMBLIES AutoRegisterInternal(AppDomain.CurrentDomain.GetAssemblies(), true); +#else + AutoRegisterInternal(new Assembly[] {this.GetType().Assembly}, true); +#endif } /// @@ -430,7 +457,11 @@ /// public void AutoRegister(bool ignoreDuplicateImplementations) { +#if APPDOMAIN_GETASSEMBLIES AutoRegisterInternal(AppDomain.CurrentDomain.GetAssemblies(), ignoreDuplicateImplementations); +#else + AutoRegisterInternal(new Assembly[] { this.GetType().Assembly }, ignoreDuplicateImplementations); +#endif } /// @@ -1638,6 +1669,10 @@ if (type.IsPrimitive) return true; +#if !UNBOUND_GENERICS_GETCONSTRUCTORS + if (type.IsGenericTypeDefinition) + return true; +#endif if ((type.GetConstructors(BindingFlags.Instance | BindingFlags.Public).Length == 0) && !(type.IsInterface || type.IsAbstract)) return true; @@ -1811,10 +1846,11 @@ } } +#if EXPRESSIONS // Attempt to construct an automatic lazy factory if possible if (IsAutomaticLazyFactoryRequest(registration.Type)) return GetLazyAutomaticFactoryRequest(registration.Type); - +#endif // Attempt unregistered construction if possible and requested if ((options.UnregisteredResolutionAction == UnregisteredResolutionActions.AttemptResolve) || (registration.Type.IsGenericType && options.UnregisteredResolutionAction == UnregisteredResolutionActions.GenericsOnly)) { @@ -1830,6 +1866,7 @@ throw new TinyIoCResolutionException(registration.Type); } +#if EXPRESSIONS private object GetLazyAutomaticFactoryRequest(Type type) { if (!type.IsGenericType) @@ -1889,7 +1926,7 @@ throw new TinyIoCResolutionException(type); } - +#endif private bool CanConstruct(ConstructorInfo ctor, NamedParameterOverloads parameters, ResolveOptions options) { if (parameters == null) diff -r 9758b42893214968c3267a8a34383d124f1ba008 -r d55f4c95f2e3a014de9f1d4594352914c22629b8 TinyIoC/TinyIoC.cs.orig --- a/TinyIoC/TinyIoC.cs.orig Thu Apr 01 19:04:20 2010 +0100 +++ b/TinyIoC/TinyIoC.cs.orig Mon Apr 05 17:50:44 2010 +0100 @@ -13,6 +13,10 @@ // FITNESS FOR A PARTICULAR PURPOSE. //=============================================================================== +// Uncomment this line if you want the container to automatically +// register the TinyMessenger messenger/event aggregator +//#define TINYMESSENGER + using System; using System.Collections.Generic; using System.Linq; @@ -87,6 +91,8 @@ item.Dispose(); } } + + GC.SuppressFinalize(this); } #endregion @@ -127,6 +133,7 @@ public class TinyIoCRegistrationException : Exception { private const string CONVERT_ERROR_TEXT = "Cannot convert current registration of {0} to {1}"; + private const string INVALID_TYPE_REGISTRATION_TEXT = "Unable to register {0}. Cannot register interfaces or abstract classes as an implementation type or without an implementation type specified"; public TinyIoCRegistrationException(Type type, string method) : base(String.Format(CONVERT_ERROR_TEXT, type.FullName, method)) @@ -137,6 +144,16 @@ : base(String.Format(CONVERT_ERROR_TEXT, type.FullName, method), innerException) { } + + public TinyIoCRegistrationException(Type type) + : base(String.Format(INVALID_TYPE_REGISTRATION_TEXT, type.FullName)) + { + } + + public TinyIoCRegistrationException(Type type, Exception innerException) + : base(String.Format(INVALID_TYPE_REGISTRATION_TEXT, type.FullName), innerException) + { + } } public class TinyIoCWeakReferenceException : Exception @@ -398,6 +415,13 @@ #endregion #region Public API + #region Child Containers + public TinyIoCContainer GetChildContainer() + { + return new TinyIoCContainer(this); + } + #endregion + #region Registration /// /// Attempt to automatically register all non-generic classes and interfaces in the current app domain. @@ -854,6 +878,187 @@ } /// + /// Attemps to resolve a type using the default options + /// + /// Type to resolve + /// Resolved type or default if resolve fails + /// True if resolved sucessfully, false otherwise + public bool TryResolve(out ResolveType resolvedType) + where ResolveType : class + { + try + { + resolvedType = this.Resolve(); + return true; + } + catch (TinyIoCResolutionException) + { + resolvedType = default(ResolveType); + return false; + } + } + + /// + /// Attemps to resolve a type using the given options + /// + /// Type to resolve + /// Resolution options + /// Resolved type or default if resolve fails + /// True if resolved sucessfully, false otherwise + public bool TryResolve(ResolveOptions options, out ResolveType resolvedType) + where ResolveType : class + { + try + { + resolvedType = this.Resolve(options); + return true; + } + catch (TinyIoCResolutionException) + { + resolvedType = default(ResolveType); + return false; + } + } + + /// + /// Attemps to resolve a type using the default options and given name + /// + /// Type to resolve + /// Name of registration + /// Resolved type or default if resolve fails + /// True if resolved sucessfully, false otherwise + public bool TryResolve(string name, out ResolveType resolvedType) + where ResolveType : class + { + try + { + resolvedType = this.Resolve(name); + return true; + } + catch (TinyIoCResolutionException) + { + resolvedType = default(ResolveType); + return false; + } + } + + /// + /// Attemps to resolve a type using the given options and name + /// + /// Type to resolve + /// Name of registration + /// Resolution options + /// Resolved type or default if resolve fails + /// True if resolved sucessfully, false otherwise + public bool TryResolve(string name, ResolveOptions options, out ResolveType resolvedType) + where ResolveType : class + { + try + { + resolvedType = this.Resolve(name, options); + return true; + } + catch (TinyIoCResolutionException) + { + resolvedType = default(ResolveType); + return false; + } + } + + /// + /// Attemps to resolve a type using the default options and supplied constructor parameters + /// + /// Type to resolve + /// User specified constructor parameters + /// Resolved type or default if resolve fails + /// True if resolved sucessfully, false otherwise + public bool TryResolve(NamedParameterOverloads parameters, out ResolveType resolvedType) + where ResolveType : class + { + try + { + resolvedType = this.Resolve(parameters); + return true; + } + catch (TinyIoCResolutionException) + { + resolvedType = default(ResolveType); + return false; + } + } + + /// + /// Attemps to resolve a type using the default options and supplied name and constructor parameters + /// + /// Type to resolve + /// Name of registration + /// User specified constructor parameters + /// Resolved type or default if resolve fails + /// True if resolved sucessfully, false otherwise + public bool TryResolve(string name, NamedParameterOverloads parameters, out ResolveType resolvedType) + where ResolveType : class + { + try + { + resolvedType = this.Resolve(name, parameters); + return true; + } + catch (TinyIoCResolutionException) + { + resolvedType = default(ResolveType); + return false; + } + } + + /// + /// Attemps to resolve a type using the supplied options and constructor parameters + /// + /// Type to resolve + /// Name of registration + /// User specified constructor parameters + /// Resolution options + /// Resolved type or default if resolve fails + /// True if resolved sucessfully, false otherwise + public bool TryResolve(NamedParameterOverloads parameters, ResolveOptions options, out ResolveType resolvedType) + where ResolveType : class + { + try + { + resolvedType = this.Resolve(parameters, options); + return true; + } + catch (TinyIoCResolutionException) + { + resolvedType = default(ResolveType); + return false; + } + } + + /// + /// Attemps to resolve a type using the supplied name, options and constructor parameters + /// + /// Type to resolve + /// Name of registration + /// User specified constructor parameters + /// Resolution options + /// Resolved type or default if resolve fails + /// True if resolved sucessfully, false otherwise + public bool TryResolve(string name, NamedParameterOverloads parameters, ResolveOptions options, out ResolveType resolvedType) + where ResolveType : class + { + try + { + resolvedType = this.Resolve(name, parameters, options); + return true; + } + catch (TinyIoCResolutionException) + { + resolvedType = default(ResolveType); + return false; + } + } + + /// /// Attempts to resolve all public property dependencies on the given object. /// /// Object to "build up" @@ -1355,7 +1560,7 @@ { var typeRegistration = obj as TypeRegistration; - if (obj == null) + if (typeRegistration == null) return false; if (this.Type != typeRegistration.Type) @@ -1382,6 +1587,12 @@ RegisterDefaultTypes(); } + + TinyIoCContainer _Parent; + private TinyIoCContainer(TinyIoCContainer parent) : this() + { + this._Parent = parent; + } #endregion #region Internal Methods @@ -1394,8 +1605,6 @@ var types = assemblies.SelectMany(a => a.GetTypes()).Where(t => !IsIgnoredType(t)).ToList(); - var sortedTypes = types.OrderBy(o => o.Name); - var concreteTypes = from type in types where (type.IsClass == true) && (type.IsAbstract == false) && (type != this.GetType() && (type.DeclaringType != this.GetType()) && (!type.IsGenericTypeDefinition)) select type; @@ -1449,9 +1658,11 @@ private void RegisterDefaultTypes() { this.Register(this); + #if TINYMESSENGER - if (parent == null) - this.Register(); + // Only register the TinyMessenger singleton if we are the root container + if (this._Parent == null) + this.Register(); #endif } @@ -1466,6 +1677,9 @@ private RegisterOptions RegisterInternal(Type registerType, Type registerImplementation, string name, ObjectFactoryBase factory) { + if (registerImplementation.IsInterface || registerImplementation.IsAbstract) + throw new TinyIoCRegistrationException(registerType); + var typeRegistration = new TypeRegistration(registerType, name); return AddUpdateRegistration(typeRegistration, factory); @@ -1514,8 +1728,9 @@ } // 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 false; + 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) @@ -1534,8 +1749,13 @@ 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 : false; + 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; } @@ -1581,7 +1801,13 @@ // Fail if requesting named resolution and settings set to fail if unresolved if (!String.IsNullOrEmpty(registration.Name) && options.NamedResolutionFailureAction == NamedResolutionFailureActions.Fail) - throw new TinyIoCResolutionException(registration.Type); + { + // 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) @@ -1610,6 +1836,10 @@ 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); } @@ -1776,7 +2006,7 @@ { property.SetValue(input, ResolveInternal(new TypeRegistration(property.PropertyType), NamedParameterOverloads.Default, resolveOptions), null); } - catch (Exception TinyIoCResolutionException) + catch (TinyIoCResolutionException) { // Catch any resolution errors and ignore them } @@ -1789,6 +2019,8 @@ public void Dispose() { _RegisteredTypes.Dispose(); + + GC.SuppressFinalize(this); } #endregion