From c9d9810c282dd702a17f62b2b9211ab60e7cf36b Mon Sep 17 00:00:00 2001 From: Markus Ewald Date: Wed, 27 May 2009 19:55:06 +0000 Subject: [PATCH] Added prototype factory - a factory which created instances by cloning a prototype instance; redesigned the service manager to query types from an ITypeLister interface instead of tightly coupling it with the PluginRepository class; added type listers that list all assemblies in an app domain, in a PluginRepository and in a predefined list; renamed the IProgressTrackingService to IProgressCollectingService to make it perfectly clear which service is for which purpose; added Instancing.None to disallow the service manager from providing a certain contract; added CPL headers where they were missing git-svn-id: file:///srv/devel/repo-conversion/nusu@140 d2e56fa2-650e-0410-a79f-9358c0239efd --- Nuclex.Support (Xbox 360).csproj | 26 +- Nuclex.Support.csproj | 26 +- Source/Plugins/PrototypeFactory.Test.cs | 141 +++++++++++ Source/Plugins/PrototypeFactory.cs | 54 +++++ Source/Services/AppDomainTypeLister.Test.cs | 73 ++++++ Source/Services/AppDomainTypeLister.cs | 59 +++++ Source/Services/AssemblyTypeLister.Test.cs | 138 +++++++++++ Source/Services/AssemblyTypeLister.cs | 143 +++++++++++ Source/Services/ITypeLister.cs | 42 ++++ Source/Services/Instancing.cs | 31 ++- Source/Services/PredefinedTypeLister.Test.cs | 103 ++++++++ Source/Services/PredefinedTypeLister.cs | 60 +++++ ...rvice.cs => IProgressCollectingService.cs} | 26 +- .../IProgressPublishingService.cs | 22 +- .../ProgressTracking/ITrackedProcess.cs | 22 +- .../ProgressTrackingComponent.cs | 24 +- Source/Services/RepositoryTypeLister.Test.cs | 63 +++++ Source/Services/RepositoryTypeLister.cs | 72 ++++++ Source/Services/ServiceManager.For.cs | 26 +- Source/Services/ServiceManager.Test.cs | 191 +++++++++++++++ Source/Services/ServiceManager.cs | 222 +++++++++++++++--- 21 files changed, 1516 insertions(+), 48 deletions(-) create mode 100644 Source/Plugins/PrototypeFactory.Test.cs create mode 100644 Source/Plugins/PrototypeFactory.cs create mode 100644 Source/Services/AppDomainTypeLister.Test.cs create mode 100644 Source/Services/AppDomainTypeLister.cs create mode 100644 Source/Services/AssemblyTypeLister.Test.cs create mode 100644 Source/Services/AssemblyTypeLister.cs create mode 100644 Source/Services/ITypeLister.cs create mode 100644 Source/Services/PredefinedTypeLister.Test.cs create mode 100644 Source/Services/PredefinedTypeLister.cs rename Source/Services/ProgressTracking/{IProgressTrackingService.cs => IProgressCollectingService.cs} (79%) create mode 100644 Source/Services/RepositoryTypeLister.Test.cs create mode 100644 Source/Services/RepositoryTypeLister.cs create mode 100644 Source/Services/ServiceManager.Test.cs diff --git a/Nuclex.Support (Xbox 360).csproj b/Nuclex.Support (Xbox 360).csproj index 8fb3d0c..c02e09e 100644 --- a/Nuclex.Support (Xbox 360).csproj +++ b/Nuclex.Support (Xbox 360).csproj @@ -118,11 +118,31 @@ ReverseComparer.cs + + + PrototypeFactory.cs + + + + AppDomainTypeLister.cs + + + + AssemblyTypeLister.cs + + + + PredefinedTypeLister.cs + - + + + + RepositoryTypeLister.cs + ServiceManager.cs @@ -233,6 +253,10 @@ ThreadOperation.cs + + ServiceManager.cs + + Shared.cs diff --git a/Nuclex.Support.csproj b/Nuclex.Support.csproj index d57b184..7bdb582 100644 --- a/Nuclex.Support.csproj +++ b/Nuclex.Support.csproj @@ -100,11 +100,31 @@ ReverseComparer.cs + + + PrototypeFactory.cs + + + + AppDomainTypeLister.cs + + + + AssemblyTypeLister.cs + + + + PredefinedTypeLister.cs + - + + + + RepositoryTypeLister.cs + ServiceManager.cs @@ -215,6 +235,10 @@ ThreadOperation.cs + + ServiceManager.cs + + Shared.cs diff --git a/Source/Plugins/PrototypeFactory.Test.cs b/Source/Plugins/PrototypeFactory.Test.cs new file mode 100644 index 0000000..cec4088 --- /dev/null +++ b/Source/Plugins/PrototypeFactory.Test.cs @@ -0,0 +1,141 @@ +#region CPL License +/* +Nuclex Framework +Copyright (C) 2002-2009 Nuclex Development Labs + +This library is free software; you can redistribute it and/or +modify it under the terms of the IBM Common Public License as +published by the IBM Corporation; either version 1.0 of the +License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +IBM Common Public License for more details. + +You should have received a copy of the IBM Common Public +License along with this library +*/ +#endregion + +#if UNITTEST + +using System; +using System.IO; + +using NUnit.Framework; + +namespace Nuclex.Support.Plugins { + + /// Unit Test for the prototype-based factory class + [TestFixture] + public class PrototypeFactoryTest { + + #region interface IProduct + + /// Interface used for the product in the unit test + private interface IProduct { + /// Some value associated with the product + int Value { get; } + } + + #endregion // interface IProduct + + #region class ConcretePrototype + + /// + /// Class derived from the abstract base to serve as concrete product for + /// testing the factory employer + /// + private class ConcretePrototype : IProduct, ICloneable, IDisposable { + + /// Initializes a new instance of the prototype product + /// Value that will be associated with this instance + public ConcretePrototype(int value) { + this.value = value; + } + + /// Immediately releases all resources owned by the instance + public void Dispose() { + this.disposed = true; + } + + /// Value the product has been associated with + public int Value { get { return this.value; } } + + /// Whether the prototype instance has been disposed + public bool IsDisposed { + get { return this.disposed; } + } + + /// Creates an identical copy of the instance + /// An identical copy of the instance + object ICloneable.Clone() { + return new ConcretePrototype(this.value); + } + + /// Value associated with the product + private int value; + /// Whether the instance has been disposed + private bool disposed; + + } + + #endregion // class ConcretePrototype + + /// + /// Tests whether the prototype-based factory behaves correctly by creating + /// new instances of its product using clones of its assigned prototype. + /// + [Test] + public void TestGenericInstanceCreation() { + ConcretePrototype template = new ConcretePrototype(42); + + IAbstractFactory factory = new PrototypeFactory< + IProduct, ConcretePrototype + >(template); + + IProduct factoryCreatedProduct = factory.CreateInstance(); + + Assert.AreEqual(template.Value, factoryCreatedProduct.Value); + } + + /// + /// Tests whether the prototype-based factory behaves correctly by creating + /// new instances of its product using clones of its assigned prototype. + /// + [Test] + public void TestInstanceCreation() { + ConcretePrototype template = new ConcretePrototype(42); + + IAbstractFactory factory = new PrototypeFactory< + IProduct, ConcretePrototype + >(template); + + IProduct factoryCreatedProduct = (IProduct)factory.CreateInstance(); + + Assert.AreEqual(template.Value, factoryCreatedProduct.Value); + } + + /// + /// Tests whether the prototype is disposed if it implements the IDisposable + /// interface and the factory is explicitely disposed. + /// + [Test] + public void TestPrototypeDisposal() { + ConcretePrototype template = new ConcretePrototype(42); + + PrototypeFactory factory = new PrototypeFactory< + IProduct, ConcretePrototype + >(template); + + Assert.IsFalse(template.IsDisposed); + factory.Dispose(); + Assert.IsTrue(template.IsDisposed); + } + + } + +} // namespace Nuclex.Support.Plugins + +#endif // UNITTEST diff --git a/Source/Plugins/PrototypeFactory.cs b/Source/Plugins/PrototypeFactory.cs new file mode 100644 index 0000000..d40dc8b --- /dev/null +++ b/Source/Plugins/PrototypeFactory.cs @@ -0,0 +1,54 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Nuclex.Support.Plugins { + + /// Factory that creates instances by cloning a prototype + /// Type of product created by the factory + /// Type of the prototype that will be cloned + public class PrototypeFactory : + IAbstractFactory, IAbstractFactory, IDisposable + where ProductType : class + where ConcreteType : class, ICloneable { + + /// Initializes a new prototype based factory + /// Prototype instance that will be cloned + public PrototypeFactory(ConcreteType prototype) { + this.prototype = prototype; + } + + /// + /// Creates a new instance of the type to which the factory is specialized + /// + /// The newly created instance + public ProductType CreateInstance() { + return (ProductType)this.prototype.Clone(); + } + + /// + /// Creates a new instance of the type to which the factory is specialized + /// + /// The newly created instance + object IAbstractFactory.CreateInstance() { + return this.prototype.Clone(); + } + + /// Immediately releases all resources owned by the instance + public void Dispose() { + if(this.prototype != null) { + IDisposable disposablePrototype = this.prototype as IDisposable; + if(disposablePrototype != null) { + disposablePrototype.Dispose(); + } + + this.prototype = null; + } + } + + /// The prototype object + private ConcreteType prototype; + + } + +} // namespace Nuclex.Support.Plugins diff --git a/Source/Services/AppDomainTypeLister.Test.cs b/Source/Services/AppDomainTypeLister.Test.cs new file mode 100644 index 0000000..827c2d5 --- /dev/null +++ b/Source/Services/AppDomainTypeLister.Test.cs @@ -0,0 +1,73 @@ +#region CPL License +/* +Nuclex Framework +Copyright (C) 2002-2009 Nuclex Development Labs + +This library is free software; you can redistribute it and/or +modify it under the terms of the IBM Common Public License as +published by the IBM Corporation; either version 1.0 of the +License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +IBM Common Public License for more details. + +You should have received a copy of the IBM Common Public +License along with this library +*/ +#endregion + +#if UNITTEST + +using System; +using System.Collections.Generic; +using System.Reflection; + +using NUnit.Framework; + +namespace Nuclex.Support.Services { + + /// Unit Test for the cached app domain type lister + [TestFixture] + public class AppDomainTypeListerTest { + + /// + /// Verifies that the assembly type list is generated correctly for + /// the default constructor (using the calling app domain) + /// + [Test] + public void TestDefaultConstructur() { + AppDomainTypeLister testLister = new AppDomainTypeLister(); + + Assert.That( + testLister.GetTypes(), + Has.Member(typeof(AppDomainTypeListerTest)).And.Member(typeof(Assembly)) + ); + } + + /// + /// Verifies that the assembly type list is generated correctly for + /// the full constructor + /// + [Test] + public void TestFullConstructur() { + AppDomain newAppDomain = AppDomain.CreateDomain("AppDomainTypeListerTest.Domain"); + try { + AppDomainTypeLister testLister = new AppDomainTypeLister(newAppDomain); + + Assert.That( + testLister.GetTypes(), + Has.Member(typeof(Assembly)).And.No.Member(typeof(AppDomainTypeListerTest)) + ); + } + finally { + AppDomain.Unload(newAppDomain); + } + } + + } + +} // namespace Nuclex.Support.Services + +#endif // UNITTEST diff --git a/Source/Services/AppDomainTypeLister.cs b/Source/Services/AppDomainTypeLister.cs new file mode 100644 index 0000000..42c3c4c --- /dev/null +++ b/Source/Services/AppDomainTypeLister.cs @@ -0,0 +1,59 @@ +#region CPL License +/* +Nuclex Framework +Copyright (C) 2002-2009 Nuclex Development Labs + +This library is free software; you can redistribute it and/or +modify it under the terms of the IBM Common Public License as +published by the IBM Corporation; either version 1.0 of the +License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +IBM Common Public License for more details. + +You should have received a copy of the IBM Common Public +License along with this library +*/ +#endregion + +using System; +using System.Collections.Generic; +using System.Reflection; + +namespace Nuclex.Support.Services { + +#if !XBOX360 + + /// Lists the types of all assemblies in an application domain + public class AppDomainTypeLister : AssemblyTypeLister { + + /// + /// Initializes a new application domain type lister using the application domain + /// of the calling method + /// + public AppDomainTypeLister() : this(AppDomain.CurrentDomain) { } + + /// Initializes a new application domain type lister + /// Application domain whose types will be listed + public AppDomainTypeLister(AppDomain appDomain) { + this.appDomain = appDomain; + } + + /// + /// Obtains an enumerable list of all assemblies in the application domain + /// + /// An enumerable list of the assemblies in the application domain + protected override IEnumerable GetAssemblies() { + return this.appDomain.GetAssemblies(); + } + + /// Application domain whose types the lister works on + private AppDomain appDomain; + + } + +#endif // !XBOX360 + +} // namespace Nuclex.Support.Services diff --git a/Source/Services/AssemblyTypeLister.Test.cs b/Source/Services/AssemblyTypeLister.Test.cs new file mode 100644 index 0000000..a2fdb39 --- /dev/null +++ b/Source/Services/AssemblyTypeLister.Test.cs @@ -0,0 +1,138 @@ +#region CPL License +/* +Nuclex Framework +Copyright (C) 2002-2009 Nuclex Development Labs + +This library is free software; you can redistribute it and/or +modify it under the terms of the IBM Common Public License as +published by the IBM Corporation; either version 1.0 of the +License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +IBM Common Public License for more details. + +You should have received a copy of the IBM Common Public +License along with this library +*/ +#endregion + +#if UNITTEST + +using System; +using System.Collections.Generic; +using System.Reflection; + +using NUnit.Framework; + +namespace Nuclex.Support.Services { + + /// Unit Test for the cached assembly type lister + [TestFixture] + public class AssemblyTypeListerTest { + + #region class TestAssemblyTypeLister + + /// Test implementation of a cached assembly type lister + private class TestAssemblyTypeLister : AssemblyTypeLister { + + /// Initializes a new test assembly type lister + /// Assemblies whose types will be listed + public TestAssemblyTypeLister(params Assembly[] assemblies) { + ReplaceAssemblyList(assemblies); + } + + /// Replaces the list of assemblies whose types to list + /// Assemblies whose types will be listed + public void ReplaceAssemblyList(params Assembly[] assemblies) { + this.assemblies = assemblies; + } + + /// Obtains a list of any assemblies whose types should be listed + /// A list of any assemblies whose types to list + protected override IEnumerable GetAssemblies() { + return this.assemblies; + } + + /// Assemblies whose types the test assembly type lister lists + private Assembly[] assemblies; + + } + + #endregion // class TestAssemblyTypeLister + + /// + /// Verifies that the assembly type list is generated correctly + /// + [Test] + public void TestAssemblyListGeneration() { + TestAssemblyTypeLister testLister = new TestAssemblyTypeLister( + typeof(AssemblyTypeListerTest).Assembly + ); + + Assert.That( + testLister.GetTypes(), Has.Member(typeof(AssemblyTypeListerTest)) + ); + } + + /// + /// Verifies that the assembly type list is updated when list of assemblies + /// changes inbetween calls + /// + [Test] + public void TestAssemblyListReplacement() { + TestAssemblyTypeLister testLister = new TestAssemblyTypeLister( + typeof(Assembly).Assembly, + typeof(TestAttribute).Assembly + ); + + Assert.That( + testLister.GetTypes(), + Has.Member(typeof(TestAttribute)).And.Not.Member(typeof(AssemblyTypeListerTest)) + ); + + testLister.ReplaceAssemblyList( + typeof(Assembly).Assembly, + typeof(AssemblyTypeListerTest).Assembly + ); + + Assert.That( + testLister.GetTypes(), + Has.Member(typeof(AssemblyTypeListerTest)).And.Not.Member(typeof(TestAttribute)) + ); + } + + /// + /// Verifies that the assembly type list is updated when an assembly is removed + /// from the list inbetween calls + /// + [Test] + public void TestAssemblyListRemoval() { + TestAssemblyTypeLister testLister = new TestAssemblyTypeLister( + typeof(Assembly).Assembly, + typeof(TestAttribute).Assembly, + typeof(AssemblyTypeListerTest).Assembly + ); + + Assert.That( + testLister.GetTypes(), + Has.Member(typeof(TestAttribute)).And.Member(typeof(AssemblyTypeListerTest)) + ); + + testLister.ReplaceAssemblyList( + typeof(Assembly).Assembly, + typeof(AssemblyTypeListerTest).Assembly + ); + + Assert.That( + testLister.GetTypes(), + Has.Member(typeof(AssemblyTypeListerTest)).And.Not.Member(typeof(TestAttribute)) + ); + } + + } + +} // namespace Nuclex.Support.Services + +#endif // UNITTEST diff --git a/Source/Services/AssemblyTypeLister.cs b/Source/Services/AssemblyTypeLister.cs new file mode 100644 index 0000000..82ab8bd --- /dev/null +++ b/Source/Services/AssemblyTypeLister.cs @@ -0,0 +1,143 @@ +#region CPL License +/* +Nuclex Framework +Copyright (C) 2002-2009 Nuclex Development Labs + +This library is free software; you can redistribute it and/or +modify it under the terms of the IBM Common Public License as +published by the IBM Corporation; either version 1.0 of the +License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +IBM Common Public License for more details. + +You should have received a copy of the IBM Common Public +License along with this library +*/ +#endregion + +using System; +using System.Collections.Generic; +using System.Reflection; + +namespace Nuclex.Support.Services { + + /// Lists all types in a changing set of assemblies + public abstract class AssemblyTypeLister : ITypeLister { + + #region class AssemblyTypes + + /// Caches the list of types types for an assembly + private class AssemblyTypes { + + /// Initializes a new cached assembly types list + /// Assembly the types are found in + /// Types defined in the assembly + public AssemblyTypes(Assembly assembly, Type[] types) { + this.Assembly = assembly; + this.Types = types; + } + + /// Assembly the types are found in + public Assembly Assembly; + /// Types defined in the assembly + public Type[] Types; + + } + + #endregion // class AssemblyTypes + + /// Initializes a new assembly type lister + public AssemblyTypeLister() { + this.assemblyTypes = new LinkedList(); + } + + /// Enumerates all types in the lister's assembly set + /// An enumerator over all types in the lister's assembly set + public IEnumerable GetTypes() { + + // Make sure the assembly list is filled and up-to-date + if(this.assemblyTypes.Count == 0) { + enlistAssembliesFirstTime(); + } else { + updateAssemblyList(); + } + + // Iterate over all types in all assemblies + LinkedListNode node = this.assemblyTypes.First; + while(node != null) { + Type[] types = node.Value.Types; + for(int index = 0; index < types.Length; ++index) { + yield return types[index]; + } + + node = node.Next; + } + + } + + /// Called when the assemblies set is queried for the first time + private void enlistAssembliesFirstTime() { + foreach(Assembly assembly in GetAssemblies()) { + this.assemblyTypes.AddLast(new AssemblyTypes(assembly, assembly.GetTypes())); + } + } + + /// Called to update the assembly list if it has changed + private void updateAssemblyList() { + LinkedListNode node = this.assemblyTypes.First; + + foreach(Assembly assembly in GetAssemblies()) { + + // If we reached the end of the cache, this automatically becomes a new entry + if(node == null) { + this.assemblyTypes.AddLast(new AssemblyTypes(assembly, assembly.GetTypes())); + } else { // Otherwise, figure out whether the assembly list has changed + + // Try to locate the cached entry for this assembly. If we have to skip entries, + // we know that an assembly might have been removed from the set. + LinkedListNode existingNode = node; + while(existingNode.Value.Assembly != assembly) { + existingNode = existingNode.Next; + if(existingNode == null) { + break; + } + } + + // If this assembly wasn't found in the cache, add it in the same order + // it was returned by the enumerator. + if(existingNode == null) { + this.assemblyTypes.AddBefore( + node, new AssemblyTypes(assembly, assembly.GetTypes()) + ); + } else if(existingNode != node) { // Cached assemblies were skipped, reorder + this.assemblyTypes.Remove(existingNode); + this.assemblyTypes.AddBefore(node, existingNode); + } else { // Everything as expected + node = node.Next; + } + } + + } + + // Any nodes behind the last checked node contain cached type lists for assemblies + // that are no longer in the set, so these will be removed. + while(node != null) { + LinkedListNode nextNode = node.Next; + this.assemblyTypes.Remove(node); + node = nextNode; + } + } + + /// Obtains a list of any assemblies whose types should be listed + /// A list of any assemblies whose types to list + protected abstract IEnumerable GetAssemblies(); + + /// Cached assembly type lists + private LinkedList assemblyTypes; + + } + +} // namespace Nuclex.Support.Services diff --git a/Source/Services/ITypeLister.cs b/Source/Services/ITypeLister.cs new file mode 100644 index 0000000..e3fecee --- /dev/null +++ b/Source/Services/ITypeLister.cs @@ -0,0 +1,42 @@ +#region CPL License +/* +Nuclex Framework +Copyright (C) 2002-2009 Nuclex Development Labs + +This library is free software; you can redistribute it and/or +modify it under the terms of the IBM Common Public License as +published by the IBM Corporation; either version 1.0 of the +License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +IBM Common Public License for more details. + +You should have received a copy of the IBM Common Public +License along with this library +*/ +#endregion + +using System; +using System.Collections.Generic; +using System.Reflection; + +using Nuclex.Support.Plugins; + +namespace Nuclex.Support.Services { + + /// + /// Provides a type list the service manager uses to locate components + /// + public interface ITypeLister { + + /// + /// Returns an enumerable list of types that will be checked by the service manager + /// + /// An enumerable list of types for the service manager + IEnumerable GetTypes(); + + } + +} // namespace Nuclex.Support.Services diff --git a/Source/Services/Instancing.cs b/Source/Services/Instancing.cs index 8a40220..cc06de9 100644 --- a/Source/Services/Instancing.cs +++ b/Source/Services/Instancing.cs @@ -1,4 +1,24 @@ -using System; +#region CPL License +/* +Nuclex Framework +Copyright (C) 2002-2009 Nuclex Development Labs + +This library is free software; you can redistribute it and/or +modify it under the terms of the IBM Common Public License as +published by the IBM Corporation; either version 1.0 of the +License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +IBM Common Public License for more details. + +You should have received a copy of the IBM Common Public +License along with this library +*/ +#endregion + +using System; using System.Collections.Generic; using Nuclex.Support.Plugins; @@ -7,12 +27,19 @@ namespace Nuclex.Support.Services { /// Modes in which services can be instantiated public enum Instancing { + + /// Disallow any service from being created for a contract + Never, + /// There will only be one service in the whole process Singleton, + /// Each thread will be assigned its own service InstancePerThread, + /// A new service will be created each time it is queried for Factory + } -} // namespace Nuclex.Support.DependencyInjection +} // namespace Nuclex.Support.Services diff --git a/Source/Services/PredefinedTypeLister.Test.cs b/Source/Services/PredefinedTypeLister.Test.cs new file mode 100644 index 0000000..187d165 --- /dev/null +++ b/Source/Services/PredefinedTypeLister.Test.cs @@ -0,0 +1,103 @@ +#region CPL License +/* +Nuclex Framework +Copyright (C) 2002-2009 Nuclex Development Labs + +This library is free software; you can redistribute it and/or +modify it under the terms of the IBM Common Public License as +published by the IBM Corporation; either version 1.0 of the +License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +IBM Common Public License for more details. + +You should have received a copy of the IBM Common Public +License along with this library +*/ +#endregion + +#if UNITTEST + +using System; +using System.Collections.Generic; +using System.Reflection; + +using NUnit.Framework; + +namespace Nuclex.Support.Services { + + /// Unit Test for the predefined type lister + [TestFixture] + public class PredefinedTypeListerTest { + + /// + /// Verifies that the type lister correctly takes over a list of types + /// supplied manually to the constructor + /// + [Test] + public void TestPredefinedTypesFromParams() { + ITypeLister testLister = new PredefinedTypeLister( + typeof(PredefinedTypeListerTest), typeof(TestAttribute) + ); + + Assert.That( + testLister.GetTypes(), + Has.Member(typeof(PredefinedTypeListerTest)).And.Member(typeof(TestAttribute)) + ); + } + + /// + /// Verifies that the type lister correctly takes over a list of types + /// supplied as an enumerable list to the constructor + /// + [Test] + public void TestPredefinedTypesFromEnumerable() { + IEnumerable types = typeof(PredefinedTypeListerTest).Assembly.GetTypes(); + ITypeLister testLister = new PredefinedTypeLister(types); + + Assert.That( + testLister.GetTypes(), Has.Member(typeof(PredefinedTypeListerTest)) + ); + } + + /// + /// Verifies that types can be removed from the type lister + /// + [Test] + public void TestRemoveTypesFromLister() { + PredefinedTypeLister testLister = new PredefinedTypeLister( + typeof(PredefinedTypeListerTest).Assembly.GetTypes() + ); + + Assert.That( + testLister.GetTypes(), Has.Member(typeof(PredefinedTypeListerTest)) + ); + testLister.Types.Remove(typeof(PredefinedTypeListerTest)); + Assert.That( + testLister.GetTypes(), Has.No.Member(typeof(PredefinedTypeListerTest)) + ); + } + + /// + /// Verifies that types can be added to the type lister + /// + [Test] + public void TestAddTypesToLister() { + PredefinedTypeLister testLister = new PredefinedTypeLister(); + + Assert.That( + testLister.GetTypes(), Has.No.Member(typeof(TestAttribute)) + ); + testLister.Types.Add(typeof(TestAttribute)); + Assert.That( + testLister.GetTypes(), Has.Member(typeof(TestAttribute)) + ); + } + + } + +} // namespace Nuclex.Support.Services + +#endif // UNITTEST diff --git a/Source/Services/PredefinedTypeLister.cs b/Source/Services/PredefinedTypeLister.cs new file mode 100644 index 0000000..cc539f4 --- /dev/null +++ b/Source/Services/PredefinedTypeLister.cs @@ -0,0 +1,60 @@ +#region CPL License +/* +Nuclex Framework +Copyright (C) 2002-2009 Nuclex Development Labs + +This library is free software; you can redistribute it and/or +modify it under the terms of the IBM Common Public License as +published by the IBM Corporation; either version 1.0 of the +License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +IBM Common Public License for more details. + +You should have received a copy of the IBM Common Public +License along with this library +*/ +#endregion + +using System; +using System.Collections.Generic; +using System.Text; + +namespace Nuclex.Support.Services { + + /// Type lister that returns a predefined list of types + public class PredefinedTypeLister : ITypeLister { + + /// Initializes a new predefined type lister + /// Types the predefined type lister will list + public PredefinedTypeLister(params Type[] types) { + this.types = new List(types); + } + + /// Initializes a new predefined type lister + /// Types the predefined type lister will list + public PredefinedTypeLister(IEnumerable types) { + this.types = new List(types); + } + + /// + /// Returns an enumerable list of types that will be checked by the service manager + /// + /// An enumerable list of types for the service manager + public IEnumerable GetTypes() { + return this.types; + } + + /// Predefined list of types the lister will list + public List Types { + get { return this.types; } + } + + /// The predefined list of types + private List types; + + } + +} // namespace Nuclex.Support.Services diff --git a/Source/Services/ProgressTracking/IProgressTrackingService.cs b/Source/Services/ProgressTracking/IProgressCollectingService.cs similarity index 79% rename from Source/Services/ProgressTracking/IProgressTrackingService.cs rename to Source/Services/ProgressTracking/IProgressCollectingService.cs index da6702d..883617e 100644 --- a/Source/Services/ProgressTracking/IProgressTrackingService.cs +++ b/Source/Services/ProgressTracking/IProgressCollectingService.cs @@ -1,4 +1,24 @@ -using System; +#region CPL License +/* +Nuclex Framework +Copyright (C) 2002-2009 Nuclex Development Labs + +This library is free software; you can redistribute it and/or +modify it under the terms of the IBM Common Public License as +published by the IBM Corporation; either version 1.0 of the +License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +IBM Common Public License for more details. + +You should have received a copy of the IBM Common Public +License along with this library +*/ +#endregion + +using System; using System.Collections.Generic; using Nuclex.Support.Tracking; @@ -6,7 +26,7 @@ using Nuclex.Support.Tracking; namespace Nuclex.Support.Services.ProgressTracking { /// Allows application-wide tracking of progress - interface IProgressTrackingService { + interface IProgressCollectingService { /// Tracks the progress of the specified transaction /// @@ -62,7 +82,7 @@ namespace Nuclex.Support.Services.ProgressTracking { /// at all, dispite adding it to the progress tracking service). /// void Untrack(Transaction transaction); - + } } // namespace Nuclex.Support.DependencyInjection.ProgressTracking diff --git a/Source/Services/ProgressTracking/IProgressPublishingService.cs b/Source/Services/ProgressTracking/IProgressPublishingService.cs index 1af810e..3d5969e 100644 --- a/Source/Services/ProgressTracking/IProgressPublishingService.cs +++ b/Source/Services/ProgressTracking/IProgressPublishingService.cs @@ -1,4 +1,24 @@ -using System; +#region CPL License +/* +Nuclex Framework +Copyright (C) 2002-2009 Nuclex Development Labs + +This library is free software; you can redistribute it and/or +modify it under the terms of the IBM Common Public License as +published by the IBM Corporation; either version 1.0 of the +License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +IBM Common Public License for more details. + +You should have received a copy of the IBM Common Public +License along with this library +*/ +#endregion + +using System; using System.Collections.Generic; using Nuclex.Support.Tracking; diff --git a/Source/Services/ProgressTracking/ITrackedProcess.cs b/Source/Services/ProgressTracking/ITrackedProcess.cs index f26da31..1a49cc3 100644 --- a/Source/Services/ProgressTracking/ITrackedProcess.cs +++ b/Source/Services/ProgressTracking/ITrackedProcess.cs @@ -1,4 +1,24 @@ -using System; +#region CPL License +/* +Nuclex Framework +Copyright (C) 2002-2009 Nuclex Development Labs + +This library is free software; you can redistribute it and/or +modify it under the terms of the IBM Common Public License as +published by the IBM Corporation; either version 1.0 of the +License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +IBM Common Public License for more details. + +You should have received a copy of the IBM Common Public +License along with this library +*/ +#endregion + +using System; using System.Collections.Generic; using Nuclex.Support.Tracking; diff --git a/Source/Services/ProgressTracking/ProgressTrackingComponent.cs b/Source/Services/ProgressTracking/ProgressTrackingComponent.cs index bc91fe9..f610a19 100644 --- a/Source/Services/ProgressTracking/ProgressTrackingComponent.cs +++ b/Source/Services/ProgressTracking/ProgressTrackingComponent.cs @@ -1,4 +1,24 @@ -using System; +#region CPL License +/* +Nuclex Framework +Copyright (C) 2002-2009 Nuclex Development Labs + +This library is free software; you can redistribute it and/or +modify it under the terms of the IBM Common Public License as +published by the IBM Corporation; either version 1.0 of the +License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +IBM Common Public License for more details. + +You should have received a copy of the IBM Common Public +License along with this library +*/ +#endregion + +using System; using System.Collections.Generic; using Nuclex.Support.Tracking; @@ -8,7 +28,7 @@ namespace Nuclex.Support.Services.ProgressTracking { #if false /// Tracks the progress of running background processes public class ProgressTrackingComponent : - IProgressTrackingService, + IProgressCollectingService, IProgressPublishingService { /// Fired when the overall progress changes diff --git a/Source/Services/RepositoryTypeLister.Test.cs b/Source/Services/RepositoryTypeLister.Test.cs new file mode 100644 index 0000000..aaa08a4 --- /dev/null +++ b/Source/Services/RepositoryTypeLister.Test.cs @@ -0,0 +1,63 @@ +#region CPL License +/* +Nuclex Framework +Copyright (C) 2002-2009 Nuclex Development Labs + +This library is free software; you can redistribute it and/or +modify it under the terms of the IBM Common Public License as +published by the IBM Corporation; either version 1.0 of the +License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +IBM Common Public License for more details. + +You should have received a copy of the IBM Common Public +License along with this library +*/ +#endregion + +#if UNITTEST + +using System; +using System.Collections.Generic; +using System.Reflection; + +using NUnit.Framework; + +namespace Nuclex.Support.Services { + + /// Unit Test for the cached assembly repository type lister + [TestFixture] + public class RepositoryTypeListerTest { + + /// + /// Tests whether the repository lister can cope with an empty repository + /// + [Test] + public void TestEmptyLister() { + RepositoryTypeLister testLister = new RepositoryTypeLister(); + + Assert.That(testLister.GetTypes(), Is.Empty); + } + + /// + /// Tests whether the repository lister notices an updated repository + /// + [Test] + public void TestLateAdd() { + RepositoryTypeLister testLister = new RepositoryTypeLister(); + testLister.Repository.AddAssembly(typeof(RepositoryTypeListerTest).Assembly); + + Assert.That( + testLister.GetTypes(), + Has.Member(typeof(RepositoryTypeListerTest)) + ); + } + + } + +} // namespace Nuclex.Support.Services + +#endif // UNITTEST diff --git a/Source/Services/RepositoryTypeLister.cs b/Source/Services/RepositoryTypeLister.cs new file mode 100644 index 0000000..826eb32 --- /dev/null +++ b/Source/Services/RepositoryTypeLister.cs @@ -0,0 +1,72 @@ +#region CPL License +/* +Nuclex Framework +Copyright (C) 2002-2009 Nuclex Development Labs + +This library is free software; you can redistribute it and/or +modify it under the terms of the IBM Common Public License as +published by the IBM Corporation; either version 1.0 of the +License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +IBM Common Public License for more details. + +You should have received a copy of the IBM Common Public +License along with this library +*/ +#endregion + +using System; +using System.Collections.Generic; +using System.Reflection; + +using Nuclex.Support.Plugins; + +namespace Nuclex.Support.Services { + + /// + /// Lists the types of all assemblies contained in an assembly repository + /// + public class RepositoryTypeLister : AssemblyTypeLister { + + /// + /// Initializes a new repository type lister using a new repository + /// + public RepositoryTypeLister() : this(new PluginRepository()) { } + + /// + /// Initializes a new repository type lister using an existing repository + /// + /// + /// Repository containing the assemblies whose types will be listed + /// + public RepositoryTypeLister(PluginRepository repository) { + this.repository = repository; + } + + /// + /// Returns an enumerable list of the assemblies in the repository + /// + /// An enumerable list of the assemblies in the repository + protected override IEnumerable GetAssemblies() { + return this.repository.LoadedAssemblies; + } + + /// + /// The assembly repository containing the assemblies whose types the lister + /// operates on. + /// + public PluginRepository Repository { + get { return this.repository; } + } + + /// + /// Repository containing the assemblies with the type lister's types + /// + private PluginRepository repository; + + } + +} // namespace Nuclex.Support.Services diff --git a/Source/Services/ServiceManager.For.cs b/Source/Services/ServiceManager.For.cs index 3b7c003..a6f10c9 100644 --- a/Source/Services/ServiceManager.For.cs +++ b/Source/Services/ServiceManager.For.cs @@ -1,4 +1,24 @@ -using System; +#region CPL License +/* +Nuclex Framework +Copyright (C) 2002-2009 Nuclex Development Labs + +This library is free software; you can redistribute it and/or +modify it under the terms of the IBM Common Public License as +published by the IBM Corporation; either version 1.0 of the +License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +IBM Common Public License for more details. + +You should have received a copy of the IBM Common Public +License along with this library +*/ +#endregion + +using System; using System.Collections.Generic; using System.Text; @@ -9,7 +29,6 @@ namespace Nuclex.Support.Services { #region class ForContext - // TODO: Rename to "On" to avoid confusion with concept of for loop? /// Manages the context of the "For" modifier public class ForContext { @@ -52,7 +71,6 @@ namespace Nuclex.Support.Services { #region class ForContext<> - // TODO: Rename to "On" to avoid confusion with concept of for loop? /// Manages the context of the "For" modifier public class ForContext : ForContext { @@ -93,4 +111,4 @@ namespace Nuclex.Support.Services { } #endif -} // namespace Nuclex.Support.DependencyInjection +} // namespace Nuclex.Support.Services diff --git a/Source/Services/ServiceManager.Test.cs b/Source/Services/ServiceManager.Test.cs new file mode 100644 index 0000000..b7a52cf --- /dev/null +++ b/Source/Services/ServiceManager.Test.cs @@ -0,0 +1,191 @@ +#region CPL License +/* +Nuclex Framework +Copyright (C) 2002-2009 Nuclex Development Labs + +This library is free software; you can redistribute it and/or +modify it under the terms of the IBM Common Public License as +published by the IBM Corporation; either version 1.0 of the +License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +IBM Common Public License for more details. + +You should have received a copy of the IBM Common Public +License along with this library +*/ +#endregion + +using System; +using System.IO; + +#if UNITTEST + +using NUnit.Framework; + +namespace Nuclex.Support.Services { + + /// Unit Test for the service manager class + [TestFixture] + public class ServiceManagerTest { + + #region interface IHelloContract + + /// A simple contract interface used for testing + public interface IHelloContract { } + + #endregion // interface IHelloContract + + #region interface IWorldContract + + /// Another simple contract interface used for testing + public interface IWorldContract { } + + #endregion // interface IWorldContract + + #region interface IHaveNoImplementation + + /// A contract interface that is not implementated anywhere + public interface IHaveNoImplementation { } + + #endregion // interface IHaveNoImplementation + + #region class HelloComponent + + /// Test component that implements the hello contract + public class HelloComponent : IHelloContract { } + + #endregion // class HelloComponent + + #region class WorldComponent + + /// + /// Test component that implements the world contract and requires + /// an implementation of the hello contract + /// + public class WorldComponent : IWorldContract, IHelloContract { + /// Initializes a new world component + /// + /// Array of hello contract implementations that will be used + /// + public WorldComponent(IHelloContract[] helloContracts) { } + } + + #endregion // class WorldComponent + + #region class IncompleteComponent + + /// + /// Test component that requires an implementation of a contract that has + /// no implementation available + /// + public class IncompleteComponent : IWorldContract { + /// Initializes the component + /// + /// Implementation of the unimplemented interface (:P) to use + /// + public IncompleteComponent(IHaveNoImplementation noImplementation) { } + } + + #endregion // class IncompleteComponent + + #region class NeedHello + + /// Component that needs an implementation of the hello contract + public class NeedHello : IWorldContract { + /// Initializes the component + /// + /// Implementation of the hello contract that will be used + /// + public NeedHello(IHelloContract helloContract) { } + } + + #endregion // class NeedHello + + #region class NeedWorld + + /// Component that needs an implementation of the world contract + public class NeedWorld : IHelloContract { + /// Initializes the component + /// + /// Implementation of the world contract that will be used + /// + public NeedWorld(IWorldContract worldContract) { } + } + + #endregion // class NeedWorld + +#if false + /// + /// Tests whether the GetComponents() method behaves correctly if it is used + /// without any assemblies loaded + /// + [Test] + public void TestGetComponentsWithoutAssembly() { + ServiceManager serviceManager = new ServiceManager(); + Assert.That(serviceManager.GetComponents(), Is.Empty); + } + + /// + /// Tests whether the GetComponents() method can locate a simple component + /// + [Test] + public void TestGetComponents() { + ServiceManager serviceManager = new ServiceManager(); + serviceManager.Repository.AddAssembly(typeof(ServiceManagerTest).Assembly); + + Assert.That( + serviceManager.GetComponents(), + Has.Member(typeof(HelloComponent)).And.Member(typeof(WorldComponent)) + ); + } + + /// + /// Tests whether the GetComponents() method correctly determines which + /// components can have their dependencies completely provided. + /// + [Test] + public void TestFilteredGetComponents() { + ServiceManager serviceManager = new ServiceManager(); + serviceManager.Repository.AddAssembly(typeof(ServiceManagerTest).Assembly); + + Assert.That( + serviceManager.GetComponents(false), + Has.Member(typeof(WorldComponent)).And.Member(typeof(IncompleteComponent)) + ); + Assert.That( + serviceManager.GetComponents(true), + Has.Member(typeof(WorldComponent)).And.No.Member(typeof(IncompleteComponent)) + ); + } + + /// + /// Tests whether the GetComponents() method can cope with two components + /// that have a circular dependency through their services. + /// + [Test] + public void TestCircularDependency() { + + } + + /// + /// Verifies that the right exception is thrown if the non-generic GetService() + /// is used on a value type + /// + [Test] + public void TestGetComponentOnValueType() { + ServiceManager serviceManager = new ServiceManager(); + serviceManager.Repository.AddAssembly(typeof(int).Assembly); + + Assert.Throws( + delegate() { serviceManager.GetService(typeof(int)); } + ); + } +#endif + } + +} // namespace Nuclex.Support.Services + +#endif // UNITTEST diff --git a/Source/Services/ServiceManager.cs b/Source/Services/ServiceManager.cs index a9baed0..d9161ba 100644 --- a/Source/Services/ServiceManager.cs +++ b/Source/Services/ServiceManager.cs @@ -1,12 +1,40 @@ -using System; +#region CPL License +/* +Nuclex Framework +Copyright (C) 2002-2009 Nuclex Development Labs + +This library is free software; you can redistribute it and/or +modify it under the terms of the IBM Common Public License as +published by the IBM Corporation; either version 1.0 of the +License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +IBM Common Public License for more details. + +You should have received a copy of the IBM Common Public +License along with this library +*/ +#endregion + +using System; using System.Collections.Generic; +using System.Diagnostics; using System.Reflection; +using System.Threading; using Nuclex.Support.Plugins; namespace Nuclex.Support.Services { #if false + + // Allow Dependency on Container + // public Foo(IServiceProvider serviceProvider) + // public Foo(IserviceLocator serviceLocator) + // public Foo(Container container) + /// /// Inversion of Control container that manages the services of an application /// @@ -56,9 +84,110 @@ namespace Nuclex.Support.Services { /// public partial class ServiceManager : IServiceProvider { + #region class Contract + + /// Stores the settings for an individual contract + private class Contract { + + /// + /// Factory by which instances of the contract implementation can be created + /// + public IAbstractFactory Factory; + + /// How instances of the implementation are to be managed + public Instancing Instancing; + + /// Single global instance of the contract implementation + /// + /// Used only if is set to Singleton + /// + public object SingletonInstance; + + /// Thread-local instance of the contract implementation + /// + /// Used only if is set to InstancePerThread + /// + public object ThreadLocalInstance { + get { + initializeThreadLocalData(); + return Thread.GetData(this.threadLocalDataSlot); + } + set { + initializeThreadLocalData(); + Thread.SetData(this.threadLocalDataSlot, value); + } + } + + /// Initializes the thread-local data slot + private void initializeThreadLocalData() { + if(this.threadLocalDataSlot == null) { + lock(this) { + if(this.threadLocalDataSlot == null) { + this.threadLocalDataSlot = Thread.AllocateDataSlot(); + } + } + } + } + + /// Arguments to be passed to the component constructor + private Dictionary arguments; + + /// Data slot for thread local storage + /// + /// We're using an explicit data slot because the ThreadStaticAttribute class + /// can only be used on static fields and also because this class is not + /// supported by the .NET Compact Framework. + /// + private volatile LocalDataStoreSlot threadLocalDataSlot; + + } + + #endregion // class Contract + +#if !XBOX360 + /// Initializes a new service manager - public ServiceManager() { - this.pluginRepository = new PluginRepository(); + /// + /// This overload will automatically use a type lister that causes all types + /// in all loaded assemblies of the calling app domain to be considered + /// by the service manager for obtaining contract implementations. + /// + public ServiceManager() : this(new AppDomainTypeLister()) { } + +#endif // !XBOX360 + + /// Initializes a new service manager + /// + /// Type lister providing the types considered by the service manager for + /// obtaining contract implementations. + /// + public ServiceManager(ITypeLister typeLister) { + this.typeLister = typeLister; + + resolveContractMethod = GetType().GetMethod( + "resolve", BindingFlags.NonPublic | BindingFlags.Instance + ); + Debug.Assert(this.resolveContractMethod.IsGenericMethodDefinition); + } + + /// + /// Returns all available implementations for the specified contract + /// + /// + /// A new enumerator for the available contract implementations + /// + public IEnumerable GetComponents() where ContractType : class { + Type contractType = typeof(ContractType); + + foreach(Type checkedType in this.typeLister.GetTypes()) { + bool isImplementationOfContract = + (!checkedType.IsAbstract) && + contractType.IsAssignableFrom(checkedType); + + if(isImplementationOfContract) { + yield return checkedType; + } + } } /// @@ -71,31 +200,30 @@ namespace Nuclex.Support.Services { /// /// A new enumerator for the available contract implementations /// - IEnumerable GetImplementations(bool completeOnly) + public IEnumerable GetComponents(bool completeOnly) where ContractType : class { - Type contractType = typeof(ContractType); + if(completeOnly) { + return filterCompleteComponents(GetComponents()); + } else { + return GetComponents(); + } + } - Assembly[] loadedAssemblies = this.pluginRepository.LoadedAssemblies.ToArray(); - for(int index = 0; index < loadedAssemblies.Length; ++index) { - Type[] assemblyTypes = loadedAssemblies[index].GetTypes(); - - for(int typeIndex = 0; typeIndex < assemblyTypes.Length; ++typeIndex) { - Type checkedType = assemblyTypes[typeIndex]; - if(contractType.IsAssignableFrom(checkedType)) { - - } - } + /// + /// Filters a list of components so only components whose dependencies can be + /// completely provided are enumerated + /// + /// Enumerable type list that will be filtered + /// + /// Only those components whose dependencies can be completely provided + /// + private IEnumerable filterCompleteComponents(IEnumerable types) { + foreach(Type type in types) { + yield return type; } - yield return null; + yield break; } - - private struct CachedContractLookUp { - public Type[] ValidComponents; - public int Version; - } - private Dictionary cachedContracts; - private int version; /// /// Allows the adjustment of the container's behavior in regard to @@ -127,11 +255,11 @@ namespace Nuclex.Support.Services { return new ForContext(this, contractType); } - // Allow Dependency on Container - // public Foo(IServiceProvider serviceProvider) - // public Foo(IserviceLocator serviceLocator) - // public Foo(Container container) - + /// Retrieves the service of the specified type + /// + /// Contract for which the service will be retrieved + /// + /// The service for the specified contract public ContractType GetService() where ContractType : class { throw new NotImplementedException(); } @@ -141,16 +269,44 @@ namespace Nuclex.Support.Services { /// Contract for which the service will be retrieved /// /// The service for the specified contract - object IServiceProvider.GetService(Type contractType) { - throw new NotImplementedException(); + public object GetService(Type contractType) { + MethodInfo methodInstance = this.resolveContractMethod.MakeGenericMethod( + new Type[] { contractType } + ); + return methodInstance.Invoke(this, null); } /// - /// Contains all assemblies partaking in the dependency injection scheme + /// Resolves all dependencies required to create a service for a contract /// - private PluginRepository pluginRepository; + /// + /// Type of contract for which to resolve the implementation + /// + /// The settings for the contract including a valid factory + private Contract resolveContract() where ContractType : class { + throw new NotImplementedException(); + } + + private Contract resolveContract(Type contractType) { + Contract contract; + if(this.contracts.TryGetValue(contractType, out contract)) { + return contract; + } + + + + throw new NotImplementedException(); + } + + /// MethodInfo for the resolve() method of this instance + private MethodInfo resolveContractMethod; + /// Lists all types partaking in the dependency injection + private ITypeLister typeLister; + /// Dictionary with settings for each individual contract + private Dictionary contracts; } + #endif -} // namespace Nuclex.Support.DependencyInjection +} // namespace Nuclex.Support.Services