diff --git a/Nuclex.Support (Xbox 360).csproj b/Nuclex.Support (Xbox 360).csproj index c02e09e..d01ac1e 100644 --- a/Nuclex.Support (Xbox 360).csproj +++ b/Nuclex.Support (Xbox 360).csproj @@ -126,14 +126,14 @@ AppDomainTypeLister.cs - - - AssemblyTypeLister.cs + + + ExplicitTypeLister.cs - - PredefinedTypeLister.cs + + MultiAssemblyTypeLister.cs @@ -143,6 +143,9 @@ RepositoryTypeLister.cs + + ServiceManager.cs + ServiceManager.cs @@ -256,7 +259,7 @@ ServiceManager.cs - + Shared.cs diff --git a/Nuclex.Support.csproj b/Nuclex.Support.csproj index 7bdb582..443ddae 100644 --- a/Nuclex.Support.csproj +++ b/Nuclex.Support.csproj @@ -108,14 +108,14 @@ AppDomainTypeLister.cs - - - AssemblyTypeLister.cs + + + ExplicitTypeLister.cs - - PredefinedTypeLister.cs + + MultiAssemblyTypeLister.cs @@ -125,6 +125,9 @@ RepositoryTypeLister.cs + + ServiceManager.cs + ServiceManager.cs @@ -238,7 +241,7 @@ ServiceManager.cs - + Shared.cs diff --git a/Source/Services/AppDomainTypeLister.cs b/Source/Services/AppDomainTypeLister.cs index 42c3c4c..4956d4f 100644 --- a/Source/Services/AppDomainTypeLister.cs +++ b/Source/Services/AppDomainTypeLister.cs @@ -27,7 +27,7 @@ namespace Nuclex.Support.Services { #if !XBOX360 /// Lists the types of all assemblies in an application domain - public class AppDomainTypeLister : AssemblyTypeLister { + public class AppDomainTypeLister : MultiAssemblyTypeLister { /// /// Initializes a new application domain type lister using the application domain diff --git a/Source/Services/PredefinedTypeLister.Test.cs b/Source/Services/ExplicitTypeLister.Test.cs similarity index 68% rename from Source/Services/PredefinedTypeLister.Test.cs rename to Source/Services/ExplicitTypeLister.Test.cs index 187d165..f4839ff 100644 --- a/Source/Services/PredefinedTypeLister.Test.cs +++ b/Source/Services/ExplicitTypeLister.Test.cs @@ -30,7 +30,7 @@ namespace Nuclex.Support.Services { /// Unit Test for the predefined type lister [TestFixture] - public class PredefinedTypeListerTest { + public class ExplicitTypeListerTest { /// /// Verifies that the type lister correctly takes over a list of types @@ -38,13 +38,13 @@ namespace Nuclex.Support.Services { /// [Test] public void TestPredefinedTypesFromParams() { - ITypeLister testLister = new PredefinedTypeLister( - typeof(PredefinedTypeListerTest), typeof(TestAttribute) + ITypeLister testLister = new ExplicitTypeLister( + typeof(ExplicitTypeListerTest), typeof(TestAttribute) ); Assert.That( testLister.GetTypes(), - Has.Member(typeof(PredefinedTypeListerTest)).And.Member(typeof(TestAttribute)) + Has.Member(typeof(ExplicitTypeListerTest)).And.Member(typeof(TestAttribute)) ); } @@ -54,11 +54,11 @@ namespace Nuclex.Support.Services { /// [Test] public void TestPredefinedTypesFromEnumerable() { - IEnumerable types = typeof(PredefinedTypeListerTest).Assembly.GetTypes(); - ITypeLister testLister = new PredefinedTypeLister(types); + IEnumerable types = typeof(ExplicitTypeListerTest).Assembly.GetTypes(); + ITypeLister testLister = new ExplicitTypeLister(types); Assert.That( - testLister.GetTypes(), Has.Member(typeof(PredefinedTypeListerTest)) + testLister.GetTypes(), Has.Member(typeof(ExplicitTypeListerTest)) ); } @@ -67,16 +67,16 @@ namespace Nuclex.Support.Services { /// [Test] public void TestRemoveTypesFromLister() { - PredefinedTypeLister testLister = new PredefinedTypeLister( - typeof(PredefinedTypeListerTest).Assembly.GetTypes() + ExplicitTypeLister testLister = new ExplicitTypeLister( + typeof(ExplicitTypeListerTest).Assembly.GetTypes() ); Assert.That( - testLister.GetTypes(), Has.Member(typeof(PredefinedTypeListerTest)) + testLister.GetTypes(), Has.Member(typeof(ExplicitTypeListerTest)) ); - testLister.Types.Remove(typeof(PredefinedTypeListerTest)); + testLister.Types.Remove(typeof(ExplicitTypeListerTest)); Assert.That( - testLister.GetTypes(), Has.No.Member(typeof(PredefinedTypeListerTest)) + testLister.GetTypes(), Has.No.Member(typeof(ExplicitTypeListerTest)) ); } @@ -85,7 +85,7 @@ namespace Nuclex.Support.Services { /// [Test] public void TestAddTypesToLister() { - PredefinedTypeLister testLister = new PredefinedTypeLister(); + ExplicitTypeLister testLister = new ExplicitTypeLister(); Assert.That( testLister.GetTypes(), Has.No.Member(typeof(TestAttribute)) diff --git a/Source/Services/PredefinedTypeLister.cs b/Source/Services/ExplicitTypeLister.cs similarity index 88% rename from Source/Services/PredefinedTypeLister.cs rename to Source/Services/ExplicitTypeLister.cs index cc539f4..728f32b 100644 --- a/Source/Services/PredefinedTypeLister.cs +++ b/Source/Services/ExplicitTypeLister.cs @@ -25,17 +25,17 @@ using System.Text; namespace Nuclex.Support.Services { /// Type lister that returns a predefined list of types - public class PredefinedTypeLister : ITypeLister { + public class ExplicitTypeLister : ITypeLister { /// Initializes a new predefined type lister /// Types the predefined type lister will list - public PredefinedTypeLister(params Type[] types) { + public ExplicitTypeLister(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) { + public ExplicitTypeLister(IEnumerable types) { this.types = new List(types); } diff --git a/Source/Services/AssemblyTypeLister.Test.cs b/Source/Services/MultiAssemblyTypeLister.Test.cs similarity index 80% rename from Source/Services/AssemblyTypeLister.Test.cs rename to Source/Services/MultiAssemblyTypeLister.Test.cs index a2fdb39..5247549 100644 --- a/Source/Services/AssemblyTypeLister.Test.cs +++ b/Source/Services/MultiAssemblyTypeLister.Test.cs @@ -30,12 +30,12 @@ namespace Nuclex.Support.Services { /// Unit Test for the cached assembly type lister [TestFixture] - public class AssemblyTypeListerTest { + public class MultiAssemblyTypeListerTest { #region class TestAssemblyTypeLister /// Test implementation of a cached assembly type lister - private class TestAssemblyTypeLister : AssemblyTypeLister { + private class TestAssemblyTypeLister : MultiAssemblyTypeLister { /// Initializes a new test assembly type lister /// Assemblies whose types will be listed @@ -68,11 +68,11 @@ namespace Nuclex.Support.Services { [Test] public void TestAssemblyListGeneration() { TestAssemblyTypeLister testLister = new TestAssemblyTypeLister( - typeof(AssemblyTypeListerTest).Assembly + typeof(MultiAssemblyTypeListerTest).Assembly ); Assert.That( - testLister.GetTypes(), Has.Member(typeof(AssemblyTypeListerTest)) + testLister.GetTypes(), Has.Member(typeof(MultiAssemblyTypeListerTest)) ); } @@ -89,17 +89,17 @@ namespace Nuclex.Support.Services { Assert.That( testLister.GetTypes(), - Has.Member(typeof(TestAttribute)).And.Not.Member(typeof(AssemblyTypeListerTest)) + Has.Member(typeof(TestAttribute)).And.Not.Member(typeof(MultiAssemblyTypeListerTest)) ); testLister.ReplaceAssemblyList( typeof(Assembly).Assembly, - typeof(AssemblyTypeListerTest).Assembly + typeof(MultiAssemblyTypeListerTest).Assembly ); Assert.That( testLister.GetTypes(), - Has.Member(typeof(AssemblyTypeListerTest)).And.Not.Member(typeof(TestAttribute)) + Has.Member(typeof(MultiAssemblyTypeListerTest)).And.Not.Member(typeof(TestAttribute)) ); } @@ -112,22 +112,22 @@ namespace Nuclex.Support.Services { TestAssemblyTypeLister testLister = new TestAssemblyTypeLister( typeof(Assembly).Assembly, typeof(TestAttribute).Assembly, - typeof(AssemblyTypeListerTest).Assembly + typeof(MultiAssemblyTypeListerTest).Assembly ); Assert.That( testLister.GetTypes(), - Has.Member(typeof(TestAttribute)).And.Member(typeof(AssemblyTypeListerTest)) + Has.Member(typeof(TestAttribute)).And.Member(typeof(MultiAssemblyTypeListerTest)) ); testLister.ReplaceAssemblyList( typeof(Assembly).Assembly, - typeof(AssemblyTypeListerTest).Assembly + typeof(MultiAssemblyTypeListerTest).Assembly ); Assert.That( testLister.GetTypes(), - Has.Member(typeof(AssemblyTypeListerTest)).And.Not.Member(typeof(TestAttribute)) + Has.Member(typeof(MultiAssemblyTypeListerTest)).And.Not.Member(typeof(TestAttribute)) ); } diff --git a/Source/Services/AssemblyTypeLister.cs b/Source/Services/MultiAssemblyTypeLister.cs similarity index 74% rename from Source/Services/AssemblyTypeLister.cs rename to Source/Services/MultiAssemblyTypeLister.cs index 82ab8bd..7d4aec7 100644 --- a/Source/Services/AssemblyTypeLister.cs +++ b/Source/Services/MultiAssemblyTypeLister.cs @@ -25,7 +25,7 @@ using System.Reflection; namespace Nuclex.Support.Services { /// Lists all types in a changing set of assemblies - public abstract class AssemblyTypeLister : ITypeLister { + public abstract class MultiAssemblyTypeLister : ITypeLister { #region class AssemblyTypes @@ -50,7 +50,7 @@ namespace Nuclex.Support.Services { #endregion // class AssemblyTypes /// Initializes a new assembly type lister - public AssemblyTypeLister() { + public MultiAssemblyTypeLister() { this.assemblyTypes = new LinkedList(); } @@ -97,7 +97,10 @@ namespace Nuclex.Support.Services { } 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. + // we know that an assembly might have been removed from the set. This will be + // handled by moved all matched assemblies to the beginning, so that when we + // finish, the assemblies after the last checked one automatically become those + // which are no longer in the set. LinkedListNode existingNode = node; while(existingNode.Value.Assembly != assembly) { existingNode = existingNode.Next; @@ -106,17 +109,33 @@ namespace Nuclex.Support.Services { } } - // If this assembly wasn't found in the cache, add it in the same order - // it was returned by the enumerator. + // Is this assembly not yet in the cache? if(existingNode == null) { + + // If this assembly wasn't found in the cache, add it in the same order + // it was returned by the enumerator. This will improve efficiency later + // since the update algorithm is designed to perform optimally if the order + // remains the same between calls. this.assemblyTypes.AddBefore( node, new AssemblyTypes(assembly, assembly.GetTypes()) ); - } else if(existingNode != node) { // Cached assemblies were skipped, reorder + + } else if(existingNode != node) { // Did we skip other cached assemblies? + + // If other cached assemblies had to be skipped, this indicates that + // the set of assemblies has changed. Move the list nodes to the same order + // in which the assemblies are returned by the enumerator. Any cached + // assemblies that have been completely removed from the set will therefore + // end up at the bottom of the list after the update has completed. this.assemblyTypes.Remove(existingNode); this.assemblyTypes.AddBefore(node, existingNode); - } else { // Everything as expected + + } else { // Assembly was found in the expected place + + // If the assembly was found in the same place as it was found during + // the last check, the assembly list is unchanged at this entry. node = node.Next; + } } diff --git a/Source/Services/ProgressTracking/ProgressTrackingComponent.cs b/Source/Services/ProgressTracking/ProgressTrackingComponent.cs index f610a19..0ec7b32 100644 --- a/Source/Services/ProgressTracking/ProgressTrackingComponent.cs +++ b/Source/Services/ProgressTracking/ProgressTrackingComponent.cs @@ -25,7 +25,8 @@ using Nuclex.Support.Tracking; namespace Nuclex.Support.Services.ProgressTracking { -#if false +#if ENABLE_SERVICEMANAGER + /// Tracks the progress of running background processes public class ProgressTrackingComponent : IProgressCollectingService, @@ -71,6 +72,7 @@ namespace Nuclex.Support.Services.ProgressTracking { } } -#endif + +#endif // ENABLE_SERVICEMANAGER } // namespace Nuclex.Support.Services.ProgressTracking diff --git a/Source/Services/RepositoryTypeLister.cs b/Source/Services/RepositoryTypeLister.cs index 826eb32..0cfaa88 100644 --- a/Source/Services/RepositoryTypeLister.cs +++ b/Source/Services/RepositoryTypeLister.cs @@ -29,7 +29,7 @@ namespace Nuclex.Support.Services { /// /// Lists the types of all assemblies contained in an assembly repository /// - public class RepositoryTypeLister : AssemblyTypeLister { + public class RepositoryTypeLister : MultiAssemblyTypeLister { /// /// Initializes a new repository type lister using a new repository diff --git a/Source/Services/ServiceManager.Analyzer.cs b/Source/Services/ServiceManager.Analyzer.cs new file mode 100644 index 0000000..6488831 --- /dev/null +++ b/Source/Services/ServiceManager.Analyzer.cs @@ -0,0 +1,53 @@ +#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 ENABLE_SERVICEMANAGER + + partial class ServiceManager { + + #region class Analyzer + + /// Analyzes Component dependencies + private static class Analyzer { + + + + public static KeyValuePair[] GetRequirements(ConstructorInfo constructor) { + ParameterInfo[] parameters = constructor.GetParameters(); + //parameters[0].IsOptional + + return null; + } + + } + + #endregion // class Analyzer + + } + +#endif // ENABLE_SERVICEMANAGER + +} // namespace Nuclex.Support.Services diff --git a/Source/Services/ServiceManager.For.cs b/Source/Services/ServiceManager.For.cs index a6f10c9..414389d 100644 --- a/Source/Services/ServiceManager.For.cs +++ b/Source/Services/ServiceManager.For.cs @@ -24,7 +24,8 @@ using System.Text; namespace Nuclex.Support.Services { -#if false +#if ENABLE_SERVICEMANAGER + partial class ServiceManager { #region class ForContext @@ -109,6 +110,7 @@ namespace Nuclex.Support.Services { #endregion // class ForContext<> } -#endif + +#endif // ENABLE_SERVICEMANAGER } // namespace Nuclex.Support.Services diff --git a/Source/Services/ServiceManager.Test.cs b/Source/Services/ServiceManager.Test.cs index b7a52cf..01edae2 100644 --- a/Source/Services/ServiceManager.Test.cs +++ b/Source/Services/ServiceManager.Test.cs @@ -21,12 +21,16 @@ License along with this library using System; using System.IO; +using Nuclex.Support.Plugins; + #if UNITTEST using NUnit.Framework; namespace Nuclex.Support.Services { +#if ENABLE_SERVICEMANAGER + /// Unit Test for the service manager class [TestFixture] public class ServiceManagerTest { @@ -117,14 +121,13 @@ namespace Nuclex.Support.Services { #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(); + ServiceManager serviceManager = new ServiceManager(new PredefinedTypeLister()); Assert.That(serviceManager.GetComponents(), Is.Empty); } @@ -133,8 +136,9 @@ namespace Nuclex.Support.Services { /// [Test] public void TestGetComponents() { - ServiceManager serviceManager = new ServiceManager(); - serviceManager.Repository.AddAssembly(typeof(ServiceManagerTest).Assembly); + RepositoryTypeLister typeLister = new RepositoryTypeLister(); + ServiceManager serviceManager = new ServiceManager(typeLister); + typeLister.Repository.AddAssembly(typeof(ServiceManagerTest).Assembly); Assert.That( serviceManager.GetComponents(), @@ -148,8 +152,9 @@ namespace Nuclex.Support.Services { /// [Test] public void TestFilteredGetComponents() { - ServiceManager serviceManager = new ServiceManager(); - serviceManager.Repository.AddAssembly(typeof(ServiceManagerTest).Assembly); + RepositoryTypeLister typeLister = new RepositoryTypeLister(); + ServiceManager serviceManager = new ServiceManager(typeLister); + typeLister.Repository.AddAssembly(typeof(ServiceManagerTest).Assembly); Assert.That( serviceManager.GetComponents(false), @@ -174,18 +179,21 @@ namespace Nuclex.Support.Services { /// Verifies that the right exception is thrown if the non-generic GetService() /// is used on a value type /// - [Test] + [Test] public void TestGetComponentOnValueType() { - ServiceManager serviceManager = new ServiceManager(); - serviceManager.Repository.AddAssembly(typeof(int).Assembly); + RepositoryTypeLister typeLister = new RepositoryTypeLister(); + ServiceManager serviceManager = new ServiceManager(typeLister); + typeLister.Repository.AddAssembly(typeof(int).Assembly); Assert.Throws( delegate() { serviceManager.GetService(typeof(int)); } ); } -#endif + } +#endif // ENABLE_SERVICEMANAGER + } // namespace Nuclex.Support.Services #endif // UNITTEST diff --git a/Source/Services/ServiceManager.cs b/Source/Services/ServiceManager.cs index d9161ba..b161a14 100644 --- a/Source/Services/ServiceManager.cs +++ b/Source/Services/ServiceManager.cs @@ -28,7 +28,7 @@ using Nuclex.Support.Plugins; namespace Nuclex.Support.Services { -#if false +#if ENABLE_SERVICEMANAGER // Allow Dependency on Container // public Foo(IServiceProvider serviceProvider) @@ -163,11 +163,7 @@ namespace Nuclex.Support.Services { /// public ServiceManager(ITypeLister typeLister) { this.typeLister = typeLister; - - resolveContractMethod = GetType().GetMethod( - "resolve", BindingFlags.NonPublic | BindingFlags.Instance - ); - Debug.Assert(this.resolveContractMethod.IsGenericMethodDefinition); + this.contracts = new Dictionary(); } /// @@ -219,10 +215,30 @@ namespace Nuclex.Support.Services { /// private IEnumerable filterCompleteComponents(IEnumerable types) { foreach(Type type in types) { - yield return type; - } - yield break; + bool isCandidate = + (!type.IsValueType) && + (!type.IsAbstract) && + (type.IsPublic || type.IsNestedPublic); + + if(isCandidate) { + + ConstructorInfo[] constructors = type.GetConstructors(BindingFlags.Public); + + + + // If a contract has been + Contract contract; + if(this.contracts.TryGetValue(type, out contract)) { + yield return type; + } else { + } + + yield return type; + + } + + } } /// @@ -256,12 +272,12 @@ namespace Nuclex.Support.Services { } /// 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(); + return (ContractType)GetService(typeof(ContractType)); } /// Retrieves the service of the specified type @@ -270,36 +286,34 @@ namespace Nuclex.Support.Services { /// /// The service for the specified contract public object GetService(Type contractType) { - MethodInfo methodInstance = this.resolveContractMethod.MakeGenericMethod( - new Type[] { contractType } - ); - return methodInstance.Invoke(this, null); + Contract c = resolveContract(contractType); + return c.Factory.CreateInstance(); // TODO: Honor the contract settings } /// /// Resolves all dependencies required to create a service for a contract /// - /// + /// /// 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; + if(contractType.IsValueType) { + throw new ArgumentException( + "Contracts have to be interfaces or classes", "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 @@ -307,6 +321,6 @@ namespace Nuclex.Support.Services { } -#endif +#endif // ENABLE_SERVICEMANAGER } // namespace Nuclex.Support.Services