Skip to content

Instantly share code, notes, and snippets.

@tompazourek
Last active September 21, 2021 16:21
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tompazourek/10668165 to your computer and use it in GitHub Desktop.
Save tompazourek/10668165 to your computer and use it in GitHub Desktop.
Simple service locator implementation. Runs on .NET 3.5 and also on .NET Compact Framework. The implementation should be thread-safe.
ServiceLocator.RegisterSingleton<ISomeClass>(() => new SomeClass(x, y, z));
ServiceLocator.Register<IOtherClass>(() => new OtherClass(x, y, z));
ServiceLocator.GetInstance<IOtherClass>(); // returns registered instance or fails
IOtherClass instance;
if (ServiceLocator.TryGetInstance<IOtherClass>(out instance)) { // if there is a registered instance
// ...
}
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Utils
{
public static class ServiceLocator
{
private static readonly IDictionary<Type, Func<object>> _typeDictionary;
private static readonly IDictionary<Type, object> _singletonDictionary;
static ServiceLocator()
{
_typeDictionary = new Dictionary<Type, Func<object>>();
_singletonDictionary = new Dictionary<Type, object>();
}
public static void RegisterSingleton<T>(Func<T> constructor) where T : class
{
if (constructor == null)
throw new ArgumentNullException("constructor");
Type type = typeof (T);
lock (_typeDictionary)
{
if (_typeDictionary.ContainsKey(type))
throw new ServiceLocatorException(string.Format("Type {0} already registered", type.FullName));
_typeDictionary.Add(type, () => EnsureSingletonInstance(constructor));
}
}
/// <summary>
/// Returns instance either from the collection of cached singletons, or creates new singleton
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="constructor"></param>
/// <returns></returns>
private static object EnsureSingletonInstance<T>(Func<T> constructor)
{
object result;
Type type = typeof (T);
lock (_singletonDictionary)
{
if (!_singletonDictionary.TryGetValue(type, out result))
{
result = _singletonDictionary[type] = constructor();
}
}
return result;
}
public static void Register<T>(Func<T> constructor) where T : class
{
if (constructor == null)
throw new ArgumentNullException("constructor");
lock (_typeDictionary)
{
Type type = typeof (T);
if (_typeDictionary.ContainsKey(type))
throw new ServiceLocatorException(string.Format("Type {0} already registered", type.FullName));
_typeDictionary.Add(type, constructor);
}
}
public static void Unregister<T>() where T : class
{
Type type = typeof (T);
lock (_typeDictionary)
_typeDictionary.Remove(type);
lock (_singletonDictionary)
_singletonDictionary.Remove(type);
}
/// <summary>
/// Returns instance registered in service locator.
/// If the instance is not registered (or is null), throws exception.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
public static T GetInstance<T>() where T : class
{
Type type = typeof (T);
Func<object> constructor;
lock (_typeDictionary)
{
if (!_typeDictionary.ContainsKey(type))
throw new ServiceLocatorException(string.Format("No instance registered for type {0}", type.FullName));
constructor = _typeDictionary[type];
}
var instance = CreateInstance<T>(constructor);
return instance;
}
/// <summary>
/// Returns instance registered in service locator.
/// If the instance is not registered, returns false.
/// If the instance is null, throws exception.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="result"></param>
/// <returns></returns>
public static bool TryGetInstance<T>(out T result) where T : class
{
Type type = typeof (T);
Func<object> constructor;
lock (_typeDictionary)
{
if (!_typeDictionary.ContainsKey(type))
{
result = null;
return false;
}
constructor = _typeDictionary[type];
}
result = CreateInstance<T>(constructor);
return true;
}
private static T CreateInstance<T>(Func<object> constructor) where T : class
{
Type type = typeof (T);
object o = constructor();
if (o == null)
{
throw new ServiceLocatorException(string.Format("Constructor of instance {0} returned null", type.FullName));
}
var instance = (T) o;
return instance;
}
}
}
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Runtime.Serialization;
using System.Text;
using System.Threading.Tasks;
namespace Utils
{
[Serializable]
public class ServiceLocatorException : Exception
{
public ServiceLocatorException()
{
}
public ServiceLocatorException(string message)
: base(message)
{
}
public ServiceLocatorException(string format, params object[] args)
: base(string.Format(format, args))
{
}
public ServiceLocatorException(string message, Exception innerException)
: base(message, innerException)
{
}
public ServiceLocatorException(string format, Exception innerException, params object[] args)
: base(string.Format(format, args), innerException)
{
}
protected ServiceLocatorException(SerializationInfo info, StreamingContext context)
: base(info, context)
{
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment