Skip to content

Instantly share code, notes, and snippets.

@jpolvora
Created November 8, 2011 21:25
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jpolvora/1349297 to your computer and use it in GitHub Desktop.
Save jpolvora/1349297 to your computer and use it in GitHub Desktop.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
namespace Metavision.Infra
{
/// <summary>
/// Service Locator simples
/// </summary>
public static class Container
{
#region Fields
/// <summary>
/// Assemblies que serão incluídos na pesquisa de tipos por string
/// </summary>
internal static readonly List<Assembly> Assemblies = new List<Assembly>();
/// <summary>
/// Dicionário que guarda instâncias singleton
/// </summary>
private static readonly Dictionary<Type, object> ActiveServices = new Dictionary<Type, object>();
/// <summary>
/// Dicionário que guarda um ponteiro para um método que fabrica um determinado tipo
/// </summary>
private static readonly Dictionary<Type, Func<object>> Factories = new Dictionary<Type, Func<object>>();
/// <summary>
/// objeto utilizado para lock de threads
/// </summary>
private static readonly object LockerObj = new object();
/// <summary>
/// Dicionário que guarda configurações para o Container
/// </summary>
private static readonly Dictionary<Type, Type> ServiceEntries = new Dictionary<Type, Type>();
/// <summary>
/// Dicionário que guarda tipos encontrados por string
/// </summary>
private static readonly Dictionary<string, Type> TypeDictionary = new Dictionary<string, Type>();
#endregion Fields
#if !SILVERLIGHT
static Container()
{
Assemblies.AddRange(AppDomain.CurrentDomain.GetAssemblies());
}
#endif
#region Methods
public static void Initialize()
{
}
public static void DisposeService<TService>()
{
if (ActiveServices.ContainsKey(typeof(TService)))
{
var disposable = ActiveServices[typeof(TService)] as IDisposable;
if (disposable != null)
{
disposable.Dispose();
}
}
ActiveServices[typeof(TService)] = null;
}
public static TServiceOut GetService<TService, TServiceOut>(bool singleton = true, object[] args = null)
where TServiceOut : class
{
return GetService(typeof(TService), singleton, args) as TServiceOut;
}
public static TService GetService<TService>(bool singleton = true, object[] args = null)
{
return (TService)GetService(typeof(TService), singleton, args);
}
public static object GetService(Type serviceType, bool singleton, object[] args = null)
{
//thread safety
lock (LockerObj)
{
if (serviceType == null) return null;
object service = null;
if (singleton && ActiveServices.ContainsKey(serviceType))
{
service = ActiveServices[serviceType];
if (service != null)
return service;
}
try
{
var typeToActivate = ServiceEntries.ContainsKey(serviceType)
? ServiceEntries[serviceType]
: serviceType;
if (!typeToActivate.IsInterface && !typeToActivate.IsAbstract)
{
service = Factories.ContainsKey(serviceType) ? Factories[serviceType]() : Activator.CreateInstance(typeToActivate, args);
}
else if (typeToActivate.IsGenericType)
{
var closedGeneric = ResolveOpenGeneric(typeToActivate);
if (closedGeneric != null)
{
service = Activator.CreateInstance(closedGeneric, args);
}
}
}
finally
{
if (singleton) ActiveServices[serviceType] = service;
}
return service;
}
}
public static void Register<TBase>(Func<TBase> factory = null)
where TBase : class
{
Register<TBase, TBase>(factory);
}
public static void Register<TBase, TConcrete>(Func<TBase> factory = null)
where TBase : class
where TConcrete : class
{
Register(typeof(TBase), typeof(TConcrete), factory as Func<object>);
}
public static void Register(Type tipoBase, Type tipoConcreto, Func<object> factory = null)
{
if (tipoBase == null) throw new ArgumentNullException("tipoBase");
if (tipoConcreto == null)
tipoConcreto = tipoBase;
ServiceEntries[tipoBase] = tipoConcreto;
ActiveServices[tipoBase] = null;
if (factory != null)
Factories[tipoBase] = factory;
}
public static TConcrete RegistraInstancia<TBase, TConcrete>(TConcrete instancia)
{
ServiceEntries[typeof(TBase)] = typeof(TConcrete);
ActiveServices[typeof(TBase)] = instancia;
return instancia;
}
public static TBase RegistraInstancia<TBase>(TBase instancia)
{
ServiceEntries[typeof(TBase)] = instancia.GetType();
ActiveServices[typeof(TBase)] = instancia;
return instancia;
}
public static void Reset()
{
ServiceEntries.Clear();
ActiveServices.Clear();
Factories.Clear();
TypeDictionary.Clear();
}
public static object TryResolve(string typeName, bool singleton)
{
var foundType = SearchType(typeName);
return foundType != null ? GetService(foundType, singleton) : null;
}
public static Type SearchType(string typeName)
{
Type foundType = null;
if (!string.IsNullOrEmpty(typeName))
{
if (TypeDictionary.ContainsKey(typeName))
{
return TypeDictionary[typeName];
}
foundType = Type.GetType(typeName, false) ?? SearchInAssemblies(typeName);
//registra mesmo que não tenha encontrado o tipo
//para da proxima vez não perder tempo
TypeDictionary[typeName] = foundType;
}
return foundType;
}
private static Type SearchInAssemblies(string typeName)
{
if (Assemblies != null)
{
foreach (var assembly in Assemblies)
{
var foundType = assembly.GetTypes().FirstOrDefault(t => t.Name == typeName);
if (foundType != null) return foundType;
}
}
return null;
}
private static Type ResolveOpenGeneric(Type type)
{
var newTypeToResolve = type.GetGenericTypeDefinition(); //openGeneric
var extractedType = type.GetGenericArguments(); //parameter
var objetoRegistrado = ServiceEntries.FirstOrDefault(o => o.Key == newTypeToResolve);
if (objetoRegistrado.Key != null)
{
var concreteType = objetoRegistrado.Value.MakeGenericType(extractedType);
return concreteType;
}
return null;
}
#endregion Methods
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment