Skip to content

Instantly share code, notes, and snippets.

@fj
Created May 25, 2010 16:34
Show Gist options
  • Save fj/413364 to your computer and use it in GitHub Desktop.
Save fj/413364 to your computer and use it in GitHub Desktop.
// 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