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
This commit is contained in:
Markus Ewald 2009-05-27 19:55:06 +00:00
parent 4e2beb71b8
commit c9d9810c28
21 changed files with 1516 additions and 48 deletions

View File

@ -118,11 +118,31 @@
<Compile Include="Source\Collections\ReverseComparer.Test.cs"> <Compile Include="Source\Collections\ReverseComparer.Test.cs">
<DependentUpon>ReverseComparer.cs</DependentUpon> <DependentUpon>ReverseComparer.cs</DependentUpon>
</Compile> </Compile>
<Compile Include="Source\Plugins\PrototypeFactory.cs" />
<Compile Include="Source\Plugins\PrototypeFactory.Test.cs">
<DependentUpon>PrototypeFactory.cs</DependentUpon>
</Compile>
<Compile Include="Source\Services\AppDomainTypeLister.cs" />
<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>
<Compile Include="Source\Services\Instancing.cs" /> <Compile Include="Source\Services\Instancing.cs" />
<Compile Include="Source\Services\ITypeLister.cs" />
<Compile Include="Source\Services\PredefinedTypeLister.Test.cs">
<DependentUpon>PredefinedTypeLister.cs</DependentUpon>
</Compile>
<Compile Include="Source\Services\ProgressTracking\IProgressPublishingService.cs" /> <Compile Include="Source\Services\ProgressTracking\IProgressPublishingService.cs" />
<Compile Include="Source\Services\ProgressTracking\IProgressTrackingService.cs" /> <Compile Include="Source\Services\ProgressTracking\IProgressCollectingService.cs" />
<Compile Include="Source\Services\ProgressTracking\ITrackedProcess.cs" /> <Compile Include="Source\Services\ProgressTracking\ITrackedProcess.cs" />
<Compile Include="Source\Services\ProgressTracking\ProgressTrackingComponent.cs" /> <Compile Include="Source\Services\ProgressTracking\ProgressTrackingComponent.cs" />
<Compile Include="Source\Services\RepositoryTypeLister.cs" />
<Compile Include="Source\Services\RepositoryTypeLister.Test.cs">
<DependentUpon>RepositoryTypeLister.cs</DependentUpon>
</Compile>
<Compile Include="Source\Services\ServiceManager.cs" /> <Compile Include="Source\Services\ServiceManager.cs" />
<Compile Include="Source\Services\ServiceManager.For.cs"> <Compile Include="Source\Services\ServiceManager.For.cs">
<DependentUpon>ServiceManager.cs</DependentUpon> <DependentUpon>ServiceManager.cs</DependentUpon>
@ -233,6 +253,10 @@
<Compile Include="Source\Scheduling\ThreadOperation.Test.cs"> <Compile Include="Source\Scheduling\ThreadOperation.Test.cs">
<DependentUpon>ThreadOperation.cs</DependentUpon> <DependentUpon>ThreadOperation.cs</DependentUpon>
</Compile> </Compile>
<Compile Include="Source\Services\ServiceManager.Test.cs">
<DependentUpon>ServiceManager.cs</DependentUpon>
</Compile>
<Compile Include="Source\Services\PredefinedTypeLister.cs" />
<Compile Include="Source\Shared.cs" /> <Compile Include="Source\Shared.cs" />
<Compile Include="Source\Shared.Test.cs"> <Compile Include="Source\Shared.Test.cs">
<DependentUpon>Shared.cs</DependentUpon> <DependentUpon>Shared.cs</DependentUpon>

View File

@ -100,11 +100,31 @@
<Compile Include="Source\Collections\ReverseComparer.Test.cs"> <Compile Include="Source\Collections\ReverseComparer.Test.cs">
<DependentUpon>ReverseComparer.cs</DependentUpon> <DependentUpon>ReverseComparer.cs</DependentUpon>
</Compile> </Compile>
<Compile Include="Source\Plugins\PrototypeFactory.cs" />
<Compile Include="Source\Plugins\PrototypeFactory.Test.cs">
<DependentUpon>PrototypeFactory.cs</DependentUpon>
</Compile>
<Compile Include="Source\Services\AppDomainTypeLister.cs" />
<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>
<Compile Include="Source\Services\Instancing.cs" /> <Compile Include="Source\Services\Instancing.cs" />
<Compile Include="Source\Services\ITypeLister.cs" />
<Compile Include="Source\Services\PredefinedTypeLister.Test.cs">
<DependentUpon>PredefinedTypeLister.cs</DependentUpon>
</Compile>
<Compile Include="Source\Services\ProgressTracking\IProgressPublishingService.cs" /> <Compile Include="Source\Services\ProgressTracking\IProgressPublishingService.cs" />
<Compile Include="Source\Services\ProgressTracking\IProgressTrackingService.cs" /> <Compile Include="Source\Services\ProgressTracking\IProgressCollectingService.cs" />
<Compile Include="Source\Services\ProgressTracking\ITrackedProcess.cs" /> <Compile Include="Source\Services\ProgressTracking\ITrackedProcess.cs" />
<Compile Include="Source\Services\ProgressTracking\ProgressTrackingComponent.cs" /> <Compile Include="Source\Services\ProgressTracking\ProgressTrackingComponent.cs" />
<Compile Include="Source\Services\RepositoryTypeLister.cs" />
<Compile Include="Source\Services\RepositoryTypeLister.Test.cs">
<DependentUpon>RepositoryTypeLister.cs</DependentUpon>
</Compile>
<Compile Include="Source\Services\ServiceManager.cs" /> <Compile Include="Source\Services\ServiceManager.cs" />
<Compile Include="Source\Services\ServiceManager.For.cs"> <Compile Include="Source\Services\ServiceManager.For.cs">
<DependentUpon>ServiceManager.cs</DependentUpon> <DependentUpon>ServiceManager.cs</DependentUpon>
@ -215,6 +235,10 @@
<Compile Include="Source\Scheduling\ThreadOperation.Test.cs"> <Compile Include="Source\Scheduling\ThreadOperation.Test.cs">
<DependentUpon>ThreadOperation.cs</DependentUpon> <DependentUpon>ThreadOperation.cs</DependentUpon>
</Compile> </Compile>
<Compile Include="Source\Services\ServiceManager.Test.cs">
<DependentUpon>ServiceManager.cs</DependentUpon>
</Compile>
<Compile Include="Source\Services\PredefinedTypeLister.cs" />
<Compile Include="Source\Shared.cs" /> <Compile Include="Source\Shared.cs" />
<Compile Include="Source\Shared.Test.cs"> <Compile Include="Source\Shared.Test.cs">
<DependentUpon>Shared.cs</DependentUpon> <DependentUpon>Shared.cs</DependentUpon>

View File

@ -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 {
/// <summary>Unit Test for the prototype-based factory class</summary>
[TestFixture]
public class PrototypeFactoryTest {
#region interface IProduct
/// <summary>Interface used for the product in the unit test</summary>
private interface IProduct {
/// <summary>Some value associated with the product</summary>
int Value { get; }
}
#endregion // interface IProduct
#region class ConcretePrototype
/// <summary>
/// Class derived from the abstract base to serve as concrete product for
/// testing the factory employer
/// </summary>
private class ConcretePrototype : IProduct, ICloneable, IDisposable {
/// <summary>Initializes a new instance of the prototype product</summary>
/// <param name="value">Value that will be associated with this instance</param>
public ConcretePrototype(int value) {
this.value = value;
}
/// <summary>Immediately releases all resources owned by the instance</summary>
public void Dispose() {
this.disposed = true;
}
/// <summary>Value the product has been associated with</summary>
public int Value { get { return this.value; } }
/// <summary>Whether the prototype instance has been disposed</summary>
public bool IsDisposed {
get { return this.disposed; }
}
/// <summary>Creates an identical copy of the instance</summary>
/// <returns>An identical copy of the instance</returns>
object ICloneable.Clone() {
return new ConcretePrototype(this.value);
}
/// <summary>Value associated with the product</summary>
private int value;
/// <summary>Whether the instance has been disposed</summary>
private bool disposed;
}
#endregion // class ConcretePrototype
/// <summary>
/// Tests whether the prototype-based factory behaves correctly by creating
/// new instances of its product using clones of its assigned prototype.
/// </summary>
[Test]
public void TestGenericInstanceCreation() {
ConcretePrototype template = new ConcretePrototype(42);
IAbstractFactory<IProduct> factory = new PrototypeFactory<
IProduct, ConcretePrototype
>(template);
IProduct factoryCreatedProduct = factory.CreateInstance();
Assert.AreEqual(template.Value, factoryCreatedProduct.Value);
}
/// <summary>
/// Tests whether the prototype-based factory behaves correctly by creating
/// new instances of its product using clones of its assigned prototype.
/// </summary>
[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);
}
/// <summary>
/// Tests whether the prototype is disposed if it implements the IDisposable
/// interface and the factory is explicitely disposed.
/// </summary>
[Test]
public void TestPrototypeDisposal() {
ConcretePrototype template = new ConcretePrototype(42);
PrototypeFactory<IProduct, ConcretePrototype> factory = new PrototypeFactory<
IProduct, ConcretePrototype
>(template);
Assert.IsFalse(template.IsDisposed);
factory.Dispose();
Assert.IsTrue(template.IsDisposed);
}
}
} // namespace Nuclex.Support.Plugins
#endif // UNITTEST

View File

@ -0,0 +1,54 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Nuclex.Support.Plugins {
/// <summary>Factory that creates instances by cloning a prototype</summary>
/// <typeparam name="ProductType">Type of product created by the factory</typeparam>
/// <typeparam name="ConcreteType">Type of the prototype that will be cloned</typeparam>
public class PrototypeFactory<ProductType, ConcreteType> :
IAbstractFactory<ProductType>, IAbstractFactory, IDisposable
where ProductType : class
where ConcreteType : class, ICloneable {
/// <summary>Initializes a new prototype based factory</summary>
/// <param name="prototype">Prototype instance that will be cloned</param>
public PrototypeFactory(ConcreteType prototype) {
this.prototype = prototype;
}
/// <summary>
/// Creates a new instance of the type to which the factory is specialized
/// </summary>
/// <returns>The newly created instance</returns>
public ProductType CreateInstance() {
return (ProductType)this.prototype.Clone();
}
/// <summary>
/// Creates a new instance of the type to which the factory is specialized
/// </summary>
/// <returns>The newly created instance</returns>
object IAbstractFactory.CreateInstance() {
return this.prototype.Clone();
}
/// <summary>Immediately releases all resources owned by the instance</summary>
public void Dispose() {
if(this.prototype != null) {
IDisposable disposablePrototype = this.prototype as IDisposable;
if(disposablePrototype != null) {
disposablePrototype.Dispose();
}
this.prototype = null;
}
}
/// <summary>The prototype object</summary>
private ConcreteType prototype;
}
} // namespace Nuclex.Support.Plugins

View File

@ -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 {
/// <summary>Unit Test for the cached app domain type lister</summary>
[TestFixture]
public class AppDomainTypeListerTest {
/// <summary>
/// Verifies that the assembly type list is generated correctly for
/// the default constructor (using the calling app domain)
/// </summary>
[Test]
public void TestDefaultConstructur() {
AppDomainTypeLister testLister = new AppDomainTypeLister();
Assert.That(
testLister.GetTypes(),
Has.Member(typeof(AppDomainTypeListerTest)).And.Member(typeof(Assembly))
);
}
/// <summary>
/// Verifies that the assembly type list is generated correctly for
/// the full constructor
/// </summary>
[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

View File

@ -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
/// <summary>Lists the types of all assemblies in an application domain</summary>
public class AppDomainTypeLister : AssemblyTypeLister {
/// <summary>
/// Initializes a new application domain type lister using the application domain
/// of the calling method
/// </summary>
public AppDomainTypeLister() : this(AppDomain.CurrentDomain) { }
/// <summary>Initializes a new application domain type lister</summary>
/// <param name="appDomain">Application domain whose types will be listed</param>
public AppDomainTypeLister(AppDomain appDomain) {
this.appDomain = appDomain;
}
/// <summary>
/// Obtains an enumerable list of all assemblies in the application domain
/// </summary>
/// <returns>An enumerable list of the assemblies in the application domain</returns>
protected override IEnumerable<Assembly> GetAssemblies() {
return this.appDomain.GetAssemblies();
}
/// <summary>Application domain whose types the lister works on</summary>
private AppDomain appDomain;
}
#endif // !XBOX360
} // namespace Nuclex.Support.Services

View File

@ -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 {
/// <summary>Unit Test for the cached assembly type lister</summary>
[TestFixture]
public class AssemblyTypeListerTest {
#region class TestAssemblyTypeLister
/// <summary>Test implementation of a cached assembly type lister</summary>
private class TestAssemblyTypeLister : AssemblyTypeLister {
/// <summary>Initializes a new test assembly type lister</summary>
/// <param name="assemblies">Assemblies whose types will be listed</param>
public TestAssemblyTypeLister(params Assembly[] assemblies) {
ReplaceAssemblyList(assemblies);
}
/// <summary>Replaces the list of assemblies whose types to list</summary>
/// <param name="assemblies">Assemblies whose types will be listed</param>
public void ReplaceAssemblyList(params Assembly[] assemblies) {
this.assemblies = assemblies;
}
/// <summary>Obtains a list of any assemblies whose types should be listed</summary>
/// <returns>A list of any assemblies whose types to list</returns>
protected override IEnumerable<Assembly> GetAssemblies() {
return this.assemblies;
}
/// <summary>Assemblies whose types the test assembly type lister lists</summary>
private Assembly[] assemblies;
}
#endregion // class TestAssemblyTypeLister
/// <summary>
/// Verifies that the assembly type list is generated correctly
/// </summary>
[Test]
public void TestAssemblyListGeneration() {
TestAssemblyTypeLister testLister = new TestAssemblyTypeLister(
typeof(AssemblyTypeListerTest).Assembly
);
Assert.That(
testLister.GetTypes(), Has.Member(typeof(AssemblyTypeListerTest))
);
}
/// <summary>
/// Verifies that the assembly type list is updated when list of assemblies
/// changes inbetween calls
/// </summary>
[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))
);
}
/// <summary>
/// Verifies that the assembly type list is updated when an assembly is removed
/// from the list inbetween calls
/// </summary>
[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

View File

@ -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 {
/// <summary>Lists all types in a changing set of assemblies</summary>
public abstract class AssemblyTypeLister : ITypeLister {
#region class AssemblyTypes
/// <summary>Caches the list of types types for an assembly</summary>
private class AssemblyTypes {
/// <summary>Initializes a new cached assembly types list</summary>
/// <param name="assembly">Assembly the types are found in</param>
/// <param name="types">Types defined in the assembly</param>
public AssemblyTypes(Assembly assembly, Type[] types) {
this.Assembly = assembly;
this.Types = types;
}
/// <summary>Assembly the types are found in</summary>
public Assembly Assembly;
/// <summary>Types defined in the assembly</summary>
public Type[] Types;
}
#endregion // class AssemblyTypes
/// <summary>Initializes a new assembly type lister</summary>
public AssemblyTypeLister() {
this.assemblyTypes = new LinkedList<AssemblyTypes>();
}
/// <summary>Enumerates all types in the lister's assembly set</summary>
/// <returns>An enumerator over all types in the lister's assembly set</returns>
public IEnumerable<Type> 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<AssemblyTypes> 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;
}
}
/// <summary>Called when the assemblies set is queried for the first time</summary>
private void enlistAssembliesFirstTime() {
foreach(Assembly assembly in GetAssemblies()) {
this.assemblyTypes.AddLast(new AssemblyTypes(assembly, assembly.GetTypes()));
}
}
/// <summary>Called to update the assembly list if it has changed</summary>
private void updateAssemblyList() {
LinkedListNode<AssemblyTypes> 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<AssemblyTypes> 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<AssemblyTypes> nextNode = node.Next;
this.assemblyTypes.Remove(node);
node = nextNode;
}
}
/// <summary>Obtains a list of any assemblies whose types should be listed</summary>
/// <returns>A list of any assemblies whose types to list</returns>
protected abstract IEnumerable<Assembly> GetAssemblies();
/// <summary>Cached assembly type lists</summary>
private LinkedList<AssemblyTypes> assemblyTypes;
}
} // namespace Nuclex.Support.Services

View File

@ -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 {
/// <summary>
/// Provides a type list the service manager uses to locate components
/// </summary>
public interface ITypeLister {
/// <summary>
/// Returns an enumerable list of types that will be checked by the service manager
/// </summary>
/// <returns>An enumerable list of types for the service manager</returns>
IEnumerable<Type> GetTypes();
}
} // namespace Nuclex.Support.Services

View File

@ -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.Collections.Generic;
using Nuclex.Support.Plugins; using Nuclex.Support.Plugins;
@ -7,12 +27,19 @@ namespace Nuclex.Support.Services {
/// <summary>Modes in which services can be instantiated</summary> /// <summary>Modes in which services can be instantiated</summary>
public enum Instancing { public enum Instancing {
/// <summary>Disallow any service from being created for a contract</summary>
Never,
/// <summary>There will only be one service in the whole process</summary> /// <summary>There will only be one service in the whole process</summary>
Singleton, Singleton,
/// <summary>Each thread will be assigned its own service</summary> /// <summary>Each thread will be assigned its own service</summary>
InstancePerThread, InstancePerThread,
/// <summary>A new service will be created each time it is queried for</summary> /// <summary>A new service will be created each time it is queried for</summary>
Factory Factory
} }
} // namespace Nuclex.Support.DependencyInjection } // namespace Nuclex.Support.Services

View File

@ -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 {
/// <summary>Unit Test for the predefined type lister</summary>
[TestFixture]
public class PredefinedTypeListerTest {
/// <summary>
/// Verifies that the type lister correctly takes over a list of types
/// supplied manually to the constructor
/// </summary>
[Test]
public void TestPredefinedTypesFromParams() {
ITypeLister testLister = new PredefinedTypeLister(
typeof(PredefinedTypeListerTest), typeof(TestAttribute)
);
Assert.That(
testLister.GetTypes(),
Has.Member(typeof(PredefinedTypeListerTest)).And.Member(typeof(TestAttribute))
);
}
/// <summary>
/// Verifies that the type lister correctly takes over a list of types
/// supplied as an enumerable list to the constructor
/// </summary>
[Test]
public void TestPredefinedTypesFromEnumerable() {
IEnumerable<Type> types = typeof(PredefinedTypeListerTest).Assembly.GetTypes();
ITypeLister testLister = new PredefinedTypeLister(types);
Assert.That(
testLister.GetTypes(), Has.Member(typeof(PredefinedTypeListerTest))
);
}
/// <summary>
/// Verifies that types can be removed from the type lister
/// </summary>
[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))
);
}
/// <summary>
/// Verifies that types can be added to the type lister
/// </summary>
[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

View File

@ -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 {
/// <summary>Type lister that returns a predefined list of types</summary>
public class PredefinedTypeLister : 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) {
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) {
this.types = new List<Type>(types);
}
/// <summary>
/// Returns an enumerable list of types that will be checked by the service manager
/// </summary>
/// <returns>An enumerable list of types for the service manager</returns>
public IEnumerable<Type> GetTypes() {
return this.types;
}
/// <summary>Predefined list of types the lister will list</summary>
public List<Type> Types {
get { return this.types; }
}
/// <summary>The predefined list of types</summary>
private List<Type> types;
}
} // namespace Nuclex.Support.Services

View File

@ -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.Collections.Generic;
using Nuclex.Support.Tracking; using Nuclex.Support.Tracking;
@ -6,7 +26,7 @@ using Nuclex.Support.Tracking;
namespace Nuclex.Support.Services.ProgressTracking { namespace Nuclex.Support.Services.ProgressTracking {
/// <summary>Allows application-wide tracking of progress</summary> /// <summary>Allows application-wide tracking of progress</summary>
interface IProgressTrackingService { interface IProgressCollectingService {
/// <summary>Tracks the progress of the specified transaction</summary> /// <summary>Tracks the progress of the specified transaction</summary>
/// <param name="transaction"> /// <param name="transaction">
@ -62,7 +82,7 @@ namespace Nuclex.Support.Services.ProgressTracking {
/// at all, dispite adding it to the progress tracking service). /// at all, dispite adding it to the progress tracking service).
/// </remarks> /// </remarks>
void Untrack(Transaction transaction); void Untrack(Transaction transaction);
} }
} // namespace Nuclex.Support.DependencyInjection.ProgressTracking } // namespace Nuclex.Support.DependencyInjection.ProgressTracking

View File

@ -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.Collections.Generic;
using Nuclex.Support.Tracking; using Nuclex.Support.Tracking;

View File

@ -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.Collections.Generic;
using Nuclex.Support.Tracking; using Nuclex.Support.Tracking;

View File

@ -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.Collections.Generic;
using Nuclex.Support.Tracking; using Nuclex.Support.Tracking;
@ -8,7 +28,7 @@ namespace Nuclex.Support.Services.ProgressTracking {
#if false #if false
/// <summary>Tracks the progress of running background processes</summary> /// <summary>Tracks the progress of running background processes</summary>
public class ProgressTrackingComponent : public class ProgressTrackingComponent :
IProgressTrackingService, IProgressCollectingService,
IProgressPublishingService { IProgressPublishingService {
/// <summary>Fired when the overall progress changes</summary> /// <summary>Fired when the overall progress changes</summary>

View File

@ -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 {
/// <summary>Unit Test for the cached assembly repository type lister</summary>
[TestFixture]
public class RepositoryTypeListerTest {
/// <summary>
/// Tests whether the repository lister can cope with an empty repository
/// </summary>
[Test]
public void TestEmptyLister() {
RepositoryTypeLister testLister = new RepositoryTypeLister();
Assert.That(testLister.GetTypes(), Is.Empty);
}
/// <summary>
/// Tests whether the repository lister notices an updated repository
/// </summary>
[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

View File

@ -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 {
/// <summary>
/// Lists the types of all assemblies contained in an assembly repository
/// </summary>
public class RepositoryTypeLister : AssemblyTypeLister {
/// <summary>
/// Initializes a new repository type lister using a new repository
/// </summary>
public RepositoryTypeLister() : this(new PluginRepository()) { }
/// <summary>
/// Initializes a new repository type lister using an existing repository
/// </summary>
/// <param name="repository">
/// Repository containing the assemblies whose types will be listed
/// </param>
public RepositoryTypeLister(PluginRepository repository) {
this.repository = repository;
}
/// <summary>
/// Returns an enumerable list of the assemblies in the repository
/// </summary>
/// <returns>An enumerable list of the assemblies in the repository</returns>
protected override IEnumerable<Assembly> GetAssemblies() {
return this.repository.LoadedAssemblies;
}
/// <summary>
/// The assembly repository containing the assemblies whose types the lister
/// operates on.
/// </summary>
public PluginRepository Repository {
get { return this.repository; }
}
/// <summary>
/// Repository containing the assemblies with the type lister's types
/// </summary>
private PluginRepository repository;
}
} // namespace Nuclex.Support.Services

View File

@ -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.Collections.Generic;
using System.Text; using System.Text;
@ -9,7 +29,6 @@ namespace Nuclex.Support.Services {
#region class ForContext #region class ForContext
// TODO: Rename to "On" to avoid confusion with concept of for loop?
/// <summary>Manages the context of the "For" modifier</summary> /// <summary>Manages the context of the "For" modifier</summary>
public class ForContext { public class ForContext {
@ -52,7 +71,6 @@ namespace Nuclex.Support.Services {
#region class ForContext<> #region class ForContext<>
// TODO: Rename to "On" to avoid confusion with concept of for loop?
/// <summary>Manages the context of the "For" modifier</summary> /// <summary>Manages the context of the "For" modifier</summary>
public class ForContext<ContractType> : ForContext { public class ForContext<ContractType> : ForContext {
@ -93,4 +111,4 @@ namespace Nuclex.Support.Services {
} }
#endif #endif
} // namespace Nuclex.Support.DependencyInjection } // namespace Nuclex.Support.Services

View File

@ -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 {
/// <summary>Unit Test for the service manager class</summary>
[TestFixture]
public class ServiceManagerTest {
#region interface IHelloContract
/// <summary>A simple contract interface used for testing</summary>
public interface IHelloContract { }
#endregion // interface IHelloContract
#region interface IWorldContract
/// <summary>Another simple contract interface used for testing</summary>
public interface IWorldContract { }
#endregion // interface IWorldContract
#region interface IHaveNoImplementation
/// <summary>A contract interface that is not implementated anywhere</summary>
public interface IHaveNoImplementation { }
#endregion // interface IHaveNoImplementation
#region class HelloComponent
/// <summary>Test component that implements the hello contract</summary>
public class HelloComponent : IHelloContract { }
#endregion // class HelloComponent
#region class WorldComponent
/// <summary>
/// Test component that implements the world contract and requires
/// an implementation of the hello contract
/// </summary>
public class WorldComponent : IWorldContract, IHelloContract {
/// <summary>Initializes a new world component</summary>
/// <param name="helloContracts">
/// Array of hello contract implementations that will be used
/// </param>
public WorldComponent(IHelloContract[] helloContracts) { }
}
#endregion // class WorldComponent
#region class IncompleteComponent
/// <summary>
/// Test component that requires an implementation of a contract that has
/// no implementation available
/// </summary>
public class IncompleteComponent : IWorldContract {
/// <summary>Initializes the component</summary>
/// <param name="noImplementation">
/// Implementation of the unimplemented interface (:P) to use
/// </param>
public IncompleteComponent(IHaveNoImplementation noImplementation) { }
}
#endregion // class IncompleteComponent
#region class NeedHello
/// <summary>Component that needs an implementation of the hello contract</summary>
public class NeedHello : IWorldContract {
/// <summary>Initializes the component</summary>
/// <param name="helloContract">
/// Implementation of the hello contract that will be used
/// </param>
public NeedHello(IHelloContract helloContract) { }
}
#endregion // class NeedHello
#region class NeedWorld
/// <summary>Component that needs an implementation of the world contract</summary>
public class NeedWorld : IHelloContract {
/// <summary>Initializes the component</summary>
/// <param name="worldContract">
/// Implementation of the world contract that will be used
/// </param>
public NeedWorld(IWorldContract worldContract) { }
}
#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();
Assert.That(serviceManager.GetComponents<IDisposable>(), Is.Empty);
}
/// <summary>
/// Tests whether the GetComponents() method can locate a simple component
/// </summary>
[Test]
public void TestGetComponents() {
ServiceManager serviceManager = new ServiceManager();
serviceManager.Repository.AddAssembly(typeof(ServiceManagerTest).Assembly);
Assert.That(
serviceManager.GetComponents<IHelloContract>(),
Has.Member(typeof(HelloComponent)).And.Member(typeof(WorldComponent))
);
}
/// <summary>
/// Tests whether the GetComponents() method correctly determines which
/// components can have their dependencies completely provided.
/// </summary>
[Test]
public void TestFilteredGetComponents() {
ServiceManager serviceManager = new ServiceManager();
serviceManager.Repository.AddAssembly(typeof(ServiceManagerTest).Assembly);
Assert.That(
serviceManager.GetComponents<IWorldContract>(false),
Has.Member(typeof(WorldComponent)).And.Member(typeof(IncompleteComponent))
);
Assert.That(
serviceManager.GetComponents<IWorldContract>(true),
Has.Member(typeof(WorldComponent)).And.No.Member(typeof(IncompleteComponent))
);
}
/// <summary>
/// Tests whether the GetComponents() method can cope with two components
/// that have a circular dependency through their services.
/// </summary>
[Test]
public void TestCircularDependency() {
}
/// <summary>
/// Verifies that the right exception is thrown if the non-generic GetService()
/// is used on a value type
/// </summary>
[Test]
public void TestGetComponentOnValueType() {
ServiceManager serviceManager = new ServiceManager();
serviceManager.Repository.AddAssembly(typeof(int).Assembly);
Assert.Throws<ArgumentException>(
delegate() { serviceManager.GetService(typeof(int)); }
);
}
#endif
}
} // namespace Nuclex.Support.Services
#endif // UNITTEST

View File

@ -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.Collections.Generic;
using System.Diagnostics;
using System.Reflection; using System.Reflection;
using System.Threading;
using Nuclex.Support.Plugins; using Nuclex.Support.Plugins;
namespace Nuclex.Support.Services { namespace Nuclex.Support.Services {
#if false #if false
// Allow Dependency on Container
// public Foo(IServiceProvider serviceProvider)
// public Foo(IserviceLocator serviceLocator)
// public Foo(Container container)
/// <summary> /// <summary>
/// Inversion of Control container that manages the services of an application /// Inversion of Control container that manages the services of an application
/// </summary> /// </summary>
@ -56,9 +84,110 @@ namespace Nuclex.Support.Services {
/// </remarks> /// </remarks>
public partial class ServiceManager : IServiceProvider { public partial class ServiceManager : IServiceProvider {
#region class Contract
/// <summary>Stores the settings for an individual contract</summary>
private class Contract {
/// <summary>
/// Factory by which instances of the contract implementation can be created
/// </summary>
public IAbstractFactory Factory;
/// <summary>How instances of the implementation are to be managed</summary>
public Instancing Instancing;
/// <summary>Single global instance of the contract implementation</summary>
/// <remarks>
/// Used only if <paramref name="Instancing" /> is set to Singleton
/// </remarks>
public object SingletonInstance;
/// <summary>Thread-local instance of the contract implementation</summary>
/// <remarks>
/// Used only if <paramref name="Instancing" />is set to InstancePerThread
/// </remarks>
public object ThreadLocalInstance {
get {
initializeThreadLocalData();
return Thread.GetData(this.threadLocalDataSlot);
}
set {
initializeThreadLocalData();
Thread.SetData(this.threadLocalDataSlot, value);
}
}
/// <summary>Initializes the thread-local data slot</summary>
private void initializeThreadLocalData() {
if(this.threadLocalDataSlot == null) {
lock(this) {
if(this.threadLocalDataSlot == null) {
this.threadLocalDataSlot = Thread.AllocateDataSlot();
}
}
}
}
/// <summary>Arguments to be passed to the component constructor</summary>
private Dictionary<string, object> arguments;
/// <summary>Data slot for thread local storage</summary>
/// <remarks>
/// 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.
/// </remarks>
private volatile LocalDataStoreSlot threadLocalDataSlot;
}
#endregion // class Contract
#if !XBOX360
/// <summary>Initializes a new service manager</summary> /// <summary>Initializes a new service manager</summary>
public ServiceManager() { /// <remarks>
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.
/// </remarks>
public ServiceManager() : this(new AppDomainTypeLister()) { }
#endif // !XBOX360
/// <summary>Initializes a new service manager</summary>
/// <param name="typeLister">
/// Type lister providing the types considered by the service manager for
/// obtaining contract implementations.
/// </param>
public ServiceManager(ITypeLister typeLister) {
this.typeLister = typeLister;
resolveContractMethod = GetType().GetMethod(
"resolve", BindingFlags.NonPublic | BindingFlags.Instance
);
Debug.Assert(this.resolveContractMethod.IsGenericMethodDefinition);
}
/// <summary>
/// Returns all available implementations for the specified contract
/// </summary>
/// <returns>
/// A new enumerator for the available contract implementations
/// </returns>
public IEnumerable<Type> GetComponents<ContractType>() 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;
}
}
} }
/// <summary> /// <summary>
@ -71,31 +200,30 @@ namespace Nuclex.Support.Services {
/// <returns> /// <returns>
/// A new enumerator for the available contract implementations /// A new enumerator for the available contract implementations
/// </returns> /// </returns>
IEnumerable<ContractType> GetImplementations<ContractType>(bool completeOnly) public IEnumerable<Type> GetComponents<ContractType>(bool completeOnly)
where ContractType : class { where ContractType : class {
Type contractType = typeof(ContractType); if(completeOnly) {
return filterCompleteComponents(GetComponents<ContractType>());
} else {
return GetComponents<ContractType>();
}
}
Assembly[] loadedAssemblies = this.pluginRepository.LoadedAssemblies.ToArray(); /// <summary>
for(int index = 0; index < loadedAssemblies.Length; ++index) { /// Filters a list of components so only components whose dependencies can be
Type[] assemblyTypes = loadedAssemblies[index].GetTypes(); /// completely provided are enumerated
/// </summary>
for(int typeIndex = 0; typeIndex < assemblyTypes.Length; ++typeIndex) { /// <param name="types">Enumerable type list that will be filtered</param>
Type checkedType = assemblyTypes[typeIndex]; /// <returns>
if(contractType.IsAssignableFrom(checkedType)) { /// Only those components whose dependencies can be completely provided
/// </returns>
} private IEnumerable<Type> filterCompleteComponents(IEnumerable<Type> 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<Type, CachedContractLookUp> cachedContracts;
private int version;
/// <summary> /// <summary>
/// Allows the adjustment of the container's behavior in regard to /// Allows the adjustment of the container's behavior in regard to
@ -127,11 +255,11 @@ namespace Nuclex.Support.Services {
return new ForContext(this, contractType); return new ForContext(this, contractType);
} }
// Allow Dependency on Container /// <summary>Retrieves the service of the specified type</summary>
// public Foo(IServiceProvider serviceProvider) /// <param name="contractType">
// public Foo(IserviceLocator serviceLocator) /// Contract for which the service will be retrieved
// public Foo(Container container) /// </param>
/// <returns>The service for the specified contract</returns>
public ContractType GetService<ContractType>() where ContractType : class { public ContractType GetService<ContractType>() where ContractType : class {
throw new NotImplementedException(); throw new NotImplementedException();
} }
@ -141,16 +269,44 @@ namespace Nuclex.Support.Services {
/// Contract for which the service will be retrieved /// Contract for which the service will be retrieved
/// </param> /// </param>
/// <returns>The service for the specified contract</returns> /// <returns>The service for the specified contract</returns>
object IServiceProvider.GetService(Type contractType) { public object GetService(Type contractType) {
throw new NotImplementedException(); MethodInfo methodInstance = this.resolveContractMethod.MakeGenericMethod(
new Type[] { contractType }
);
return methodInstance.Invoke(this, null);
} }
/// <summary> /// <summary>
/// Contains all assemblies partaking in the dependency injection scheme /// Resolves all dependencies required to create a service for a contract
/// </summary> /// </summary>
private PluginRepository pluginRepository; /// <typeparam name="ContractType">
/// Type of contract for which to resolve the implementation
/// </typeparam>
/// <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;
}
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>
private Dictionary<Type, Contract> contracts;
} }
#endif #endif
} // namespace Nuclex.Support.DependencyInjection } // namespace Nuclex.Support.Services