Created
May 25, 2010 16:34
-
-
Save fj/413364 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Given an interface (IFactory<> in this example), find everything that | |
// implements the interface and put it in a map. | |
// | |
// Usage: | |
// public interface IFactory<T> { ... } | |
// public class AppleFactory : IFactory<Apple> { ... } | |
// public class BananaFactory : IFactory<Banana> { ... } | |
// public class ChocolateFactory : IFactory<Chocolate> { ... } | |
// | |
// var m = new FactoryManager(); // Automatically scans this assembly for suitable implementations | |
// of IFactory<>. | |
// | |
// m.Get(typeof(Apple)); // Ask the manager for something that can make Apples. | |
// Client code doesn't need to know about specific Factories. | |
// Can also supply your own mappings. | |
// m.Add(typeof(Apple), new GrannySmithAppleFactory()); | |
// Code: | |
public class FactoryManager { | |
private readonly IDictionary<Type, object> _map = GenerateSuitableMappings(); | |
/// <summary> | |
/// Assemble a dictionary of factories in this assembly suitable for creating types. | |
/// </summary> | |
private static IDictionary<Type, object> GenerateSuitableMappings() { | |
Type searchTarget = typeof(IFactory<>); | |
// Return true if this interface is generic, has a definition that looks | |
// like searchTarget, and has concrete parameters. | |
Func<Type, bool> selector = i => i.IsGenericType | |
&& i.GetGenericTypeDefinition().Equals(searchTarget) | |
&& !i.ContainsGenericParameters; | |
// Find all classes in this assembly which implement the IFactory<> interface. | |
// Create a dictionary mapping the types those classes handle to instances. | |
return Assembly.GetExecutingAssembly().GetTypes() | |
.SelectMany(t => t.GetInterfaces().Where(selector), | |
(t, i) => new { Key = i.GetGenericArguments()[0], Value = t }) | |
.ToDictionary(e => e.Key, e => Activator.CreateInstance(e.Value)); | |
} | |
/// <summary> | |
/// Retrieve an <see cref="IFactory{T}"/> capable of generating a <see cref="T"/>. | |
/// </summary> | |
/// <typeparam name="T">Type to generate a factory for.</typeparam> | |
/// <returns>Suitable <see cref="IFactory{T}"/> instance.</returns> | |
public IFactory<T> Get<T>() where T : new() { | |
return (IFactory<T>) _map[typeof (T)]; | |
} | |
/// <summary> | |
/// Manually add a specified <see cref="IFactory{T}"/> to the mapping. | |
/// </summary> | |
/// <remarks> | |
/// Will erase any existing mapping for this type. | |
/// </remarks> | |
/// <typeparam name="T">Type that this factory can handle.</typeparam> | |
/// <param name="f">Factory to add.</param> | |
public void Add<T>(IFactory<T> f) where T : new() { | |
_map[typeof (T)] = f; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment