Renamed AssemblyTypeLister to MultiAssemblyTypeLister because otherwise, the name implies that it's a type lister for a single assembly; renamed PredefinedTypeLister to ExplicitTypeLister which is more intuitive; disabled all service manager code unless ENABLE_SERVICEMANAGER is defined (while it's under development); improved documentation for the multi assembly type lister; removed resolveContract() delegate and generic overloads

git-svn-id: file:///srv/devel/repo-conversion/nusu@141 d2e56fa2-650e-0410-a79f-9358c0239efd
This commit is contained in:
Markus Ewald 2009-05-28 19:50:30 +00:00
parent c9d9810c28
commit 0ada9998e2
13 changed files with 195 additions and 91 deletions

View File

@ -126,14 +126,14 @@
<Compile Include="Source\Services\AppDomainTypeLister.Test.cs">
<DependentUpon>AppDomainTypeLister.cs</DependentUpon>
</Compile>
<Compile Include="Source\Services\AssemblyTypeLister.cs" />
<Compile Include="Source\Services\AssemblyTypeLister.Test.cs">
<DependentUpon>AssemblyTypeLister.cs</DependentUpon>
<Compile Include="Source\Services\MultiAssemblyTypeLister.cs" />
<Compile Include="Source\Services\ExplicitTypeLister.Test.cs">
<DependentUpon>ExplicitTypeLister.cs</DependentUpon>
</Compile>
<Compile Include="Source\Services\Instancing.cs" />
<Compile Include="Source\Services\ITypeLister.cs" />
<Compile Include="Source\Services\PredefinedTypeLister.Test.cs">
<DependentUpon>PredefinedTypeLister.cs</DependentUpon>
<Compile Include="Source\Services\MultiAssemblyTypeLister.Test.cs">
<DependentUpon>MultiAssemblyTypeLister.cs</DependentUpon>
</Compile>
<Compile Include="Source\Services\ProgressTracking\IProgressPublishingService.cs" />
<Compile Include="Source\Services\ProgressTracking\IProgressCollectingService.cs" />
@ -143,6 +143,9 @@
<Compile Include="Source\Services\RepositoryTypeLister.Test.cs">
<DependentUpon>RepositoryTypeLister.cs</DependentUpon>
</Compile>
<Compile Include="Source\Services\ServiceManager.Analyzer.cs">
<DependentUpon>ServiceManager.cs</DependentUpon>
</Compile>
<Compile Include="Source\Services\ServiceManager.cs" />
<Compile Include="Source\Services\ServiceManager.For.cs">
<DependentUpon>ServiceManager.cs</DependentUpon>
@ -256,7 +259,7 @@
<Compile Include="Source\Services\ServiceManager.Test.cs">
<DependentUpon>ServiceManager.cs</DependentUpon>
</Compile>
<Compile Include="Source\Services\PredefinedTypeLister.cs" />
<Compile Include="Source\Services\ExplicitTypeLister.cs" />
<Compile Include="Source\Shared.cs" />
<Compile Include="Source\Shared.Test.cs">
<DependentUpon>Shared.cs</DependentUpon>

View File

@ -108,14 +108,14 @@
<Compile Include="Source\Services\AppDomainTypeLister.Test.cs">
<DependentUpon>AppDomainTypeLister.cs</DependentUpon>
</Compile>
<Compile Include="Source\Services\AssemblyTypeLister.cs" />
<Compile Include="Source\Services\AssemblyTypeLister.Test.cs">
<DependentUpon>AssemblyTypeLister.cs</DependentUpon>
<Compile Include="Source\Services\MultiAssemblyTypeLister.cs" />
<Compile Include="Source\Services\ExplicitTypeLister.Test.cs">
<DependentUpon>ExplicitTypeLister.cs</DependentUpon>
</Compile>
<Compile Include="Source\Services\Instancing.cs" />
<Compile Include="Source\Services\ITypeLister.cs" />
<Compile Include="Source\Services\PredefinedTypeLister.Test.cs">
<DependentUpon>PredefinedTypeLister.cs</DependentUpon>
<Compile Include="Source\Services\MultiAssemblyTypeLister.Test.cs">
<DependentUpon>MultiAssemblyTypeLister.cs</DependentUpon>
</Compile>
<Compile Include="Source\Services\ProgressTracking\IProgressPublishingService.cs" />
<Compile Include="Source\Services\ProgressTracking\IProgressCollectingService.cs" />
@ -125,6 +125,9 @@
<Compile Include="Source\Services\RepositoryTypeLister.Test.cs">
<DependentUpon>RepositoryTypeLister.cs</DependentUpon>
</Compile>
<Compile Include="Source\Services\ServiceManager.Analyzer.cs">
<DependentUpon>ServiceManager.cs</DependentUpon>
</Compile>
<Compile Include="Source\Services\ServiceManager.cs" />
<Compile Include="Source\Services\ServiceManager.For.cs">
<DependentUpon>ServiceManager.cs</DependentUpon>
@ -238,7 +241,7 @@
<Compile Include="Source\Services\ServiceManager.Test.cs">
<DependentUpon>ServiceManager.cs</DependentUpon>
</Compile>
<Compile Include="Source\Services\PredefinedTypeLister.cs" />
<Compile Include="Source\Services\ExplicitTypeLister.cs" />
<Compile Include="Source\Shared.cs" />
<Compile Include="Source\Shared.Test.cs">
<DependentUpon>Shared.cs</DependentUpon>

View File

@ -27,7 +27,7 @@ namespace Nuclex.Support.Services {
#if !XBOX360
/// <summary>Lists the types of all assemblies in an application domain</summary>
public class AppDomainTypeLister : AssemblyTypeLister {
public class AppDomainTypeLister : MultiAssemblyTypeLister {
/// <summary>
/// Initializes a new application domain type lister using the application domain

View File

@ -30,7 +30,7 @@ namespace Nuclex.Support.Services {
/// <summary>Unit Test for the predefined type lister</summary>
[TestFixture]
public class PredefinedTypeListerTest {
public class ExplicitTypeListerTest {
/// <summary>
/// Verifies that the type lister correctly takes over a list of types
@ -38,13 +38,13 @@ namespace Nuclex.Support.Services {
/// </summary>
[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 {
/// </summary>
[Test]
public void TestPredefinedTypesFromEnumerable() {
IEnumerable<Type> types = typeof(PredefinedTypeListerTest).Assembly.GetTypes();
ITypeLister testLister = new PredefinedTypeLister(types);
IEnumerable<Type> 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 {
/// </summary>
[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 {
/// </summary>
[Test]
public void TestAddTypesToLister() {
PredefinedTypeLister testLister = new PredefinedTypeLister();
ExplicitTypeLister testLister = new ExplicitTypeLister();
Assert.That(
testLister.GetTypes(), Has.No.Member(typeof(TestAttribute))

View File

@ -25,17 +25,17 @@ using System.Text;
namespace Nuclex.Support.Services {
/// <summary>Type lister that returns a predefined list of types</summary>
public class PredefinedTypeLister : ITypeLister {
public class ExplicitTypeLister : ITypeLister {
/// <summary>Initializes a new predefined type lister</summary>
/// <param name="types">Types the predefined type lister will list</param>
public PredefinedTypeLister(params Type[] types) {
public ExplicitTypeLister(params Type[] types) {
this.types = new List<Type>(types);
}
/// <summary>Initializes a new predefined type lister</summary>
/// <param name="types">Types the predefined type lister will list</param>
public PredefinedTypeLister(IEnumerable<Type> types) {
public ExplicitTypeLister(IEnumerable<Type> types) {
this.types = new List<Type>(types);
}

View File

@ -30,12 +30,12 @@ namespace Nuclex.Support.Services {
/// <summary>Unit Test for the cached assembly type lister</summary>
[TestFixture]
public class AssemblyTypeListerTest {
public class MultiAssemblyTypeListerTest {
#region class TestAssemblyTypeLister
/// <summary>Test implementation of a cached assembly type lister</summary>
private class TestAssemblyTypeLister : AssemblyTypeLister {
private class TestAssemblyTypeLister : MultiAssemblyTypeLister {
/// <summary>Initializes a new test assembly type lister</summary>
/// <param name="assemblies">Assemblies whose types will be listed</param>
@ -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))
);
}

View File

@ -25,7 +25,7 @@ using System.Reflection;
namespace Nuclex.Support.Services {
/// <summary>Lists all types in a changing set of assemblies</summary>
public abstract class AssemblyTypeLister : ITypeLister {
public abstract class MultiAssemblyTypeLister : ITypeLister {
#region class AssemblyTypes
@ -50,7 +50,7 @@ namespace Nuclex.Support.Services {
#endregion // class AssemblyTypes
/// <summary>Initializes a new assembly type lister</summary>
public AssemblyTypeLister() {
public MultiAssemblyTypeLister() {
this.assemblyTypes = new LinkedList<AssemblyTypes>();
}
@ -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<AssemblyTypes> 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;
}
}

View File

@ -25,7 +25,8 @@ using Nuclex.Support.Tracking;
namespace Nuclex.Support.Services.ProgressTracking {
#if false
#if ENABLE_SERVICEMANAGER
/// <summary>Tracks the progress of running background processes</summary>
public class ProgressTrackingComponent :
IProgressCollectingService,
@ -71,6 +72,7 @@ namespace Nuclex.Support.Services.ProgressTracking {
}
}
#endif
#endif // ENABLE_SERVICEMANAGER
} // namespace Nuclex.Support.Services.ProgressTracking

View File

@ -29,7 +29,7 @@ namespace Nuclex.Support.Services {
/// <summary>
/// Lists the types of all assemblies contained in an assembly repository
/// </summary>
public class RepositoryTypeLister : AssemblyTypeLister {
public class RepositoryTypeLister : MultiAssemblyTypeLister {
/// <summary>
/// Initializes a new repository type lister using a new repository

View File

@ -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
/// <summary>Analyzes Component dependencies</summary>
private static class Analyzer {
public static KeyValuePair<string, Type>[] GetRequirements(ConstructorInfo constructor) {
ParameterInfo[] parameters = constructor.GetParameters();
//parameters[0].IsOptional
return null;
}
}
#endregion // class Analyzer
}
#endif // ENABLE_SERVICEMANAGER
} // namespace Nuclex.Support.Services

View File

@ -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

View File

@ -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
/// <summary>Unit Test for the service manager class</summary>
[TestFixture]
public class ServiceManagerTest {
@ -117,14 +121,13 @@ namespace Nuclex.Support.Services {
#endregion // class NeedWorld
#if false
/// <summary>
/// Tests whether the GetComponents() method behaves correctly if it is used
/// without any assemblies loaded
/// </summary>
[Test]
public void TestGetComponentsWithoutAssembly() {
ServiceManager serviceManager = new ServiceManager();
ServiceManager serviceManager = new ServiceManager(new PredefinedTypeLister());
Assert.That(serviceManager.GetComponents<IDisposable>(), Is.Empty);
}
@ -133,8 +136,9 @@ namespace Nuclex.Support.Services {
/// </summary>
[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<IHelloContract>(),
@ -148,8 +152,9 @@ namespace Nuclex.Support.Services {
/// </summary>
[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<IWorldContract>(false),
@ -176,16 +181,19 @@ namespace Nuclex.Support.Services {
/// </summary>
[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<ArgumentException>(
delegate() { serviceManager.GetService(typeof(int)); }
);
}
#endif
}
#endif // ENABLE_SERVICEMANAGER
} // namespace Nuclex.Support.Services
#endif // UNITTEST

View File

@ -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 {
/// </param>
public ServiceManager(ITypeLister typeLister) {
this.typeLister = typeLister;
resolveContractMethod = GetType().GetMethod(
"resolve", BindingFlags.NonPublic | BindingFlags.Instance
);
Debug.Assert(this.resolveContractMethod.IsGenericMethodDefinition);
this.contracts = new Dictionary<Type, Contract>();
}
/// <summary>
@ -219,10 +215,30 @@ namespace Nuclex.Support.Services {
/// </returns>
private IEnumerable<Type> filterCompleteComponents(IEnumerable<Type> 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;
}
}
}
/// <summary>
@ -256,12 +272,12 @@ namespace Nuclex.Support.Services {
}
/// <summary>Retrieves the service of the specified type</summary>
/// <param name="contractType">
/// <typeparam name="ContractType">
/// Contract for which the service will be retrieved
/// </param>
/// </typeparam>
/// <returns>The service for the specified contract</returns>
public ContractType GetService<ContractType>() where ContractType : class {
throw new NotImplementedException();
return (ContractType)GetService(typeof(ContractType));
}
/// <summary>Retrieves the service of the specified type</summary>
@ -270,36 +286,34 @@ namespace Nuclex.Support.Services {
/// </param>
/// <returns>The service for the specified contract</returns>
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
}
/// <summary>
/// Resolves all dependencies required to create a service for a contract
/// </summary>
/// <typeparam name="ContractType">
/// <param name="contractType">
/// Type of contract for which to resolve the implementation
/// </typeparam>
/// </param>
/// <returns>The settings for the contract including a valid factory</returns>
private Contract resolveContract<ContractType>() 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();
}
/// <summary>MethodInfo for the resolve() method of this instance</summary>
private MethodInfo resolveContractMethod;
/// <summary>Lists all types partaking in the dependency injection</summary>
private ITypeLister typeLister;
/// <summary>Dictionary with settings for each individual contract</summary>
@ -307,6 +321,6 @@ namespace Nuclex.Support.Services {
}
#endif
#endif // ENABLE_SERVICEMANAGER
} // namespace Nuclex.Support.Services