Last active
September 21, 2021 16:21
-
-
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.
This file contains 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
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 | |
// ... | |
} |
This file contains 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
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; | |
} | |
} | |
} |
This file contains 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
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