Last active
January 11, 2019 17:52
-
-
Save zpqrtbnk/2667c45bddee97d8e39b7070aaf4aade to your computer and use it in GitHub Desktop.
Named Services for MS.DI
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 Microsoft.Extensions.DependencyInjection; | |
using System.Linq; | |
using System.Reflection; | |
using System.Reflection.Emit; | |
namespace MSDI | |
{ | |
public static class NamedServiceExtensions | |
{ | |
private static readonly object _locker = new object(); | |
private static readonly Dictionary<string, string> _uniqueNames = new Dictionary<string, string>(); | |
private static readonly Dictionary<string, Type> _uniqueNameTypes = new Dictionary<string, Type>(); | |
private static readonly Dictionary<string, Type> _uniqueTypes = new Dictionary<string, Type>(); | |
private static Type UniqueType(string name) | |
{ | |
if (_uniqueNameTypes.TryGetValue(name, out var type)) | |
return type; | |
var typeSignature = "MSDI.NamedService." + name; | |
var assemblyName = new AssemblyName(typeSignature); | |
var assemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run); | |
var moduleBuilder = assemblyBuilder.DefineDynamicModule("MainModule"); | |
var typeBuilder = moduleBuilder.DefineType(typeSignature, | |
TypeAttributes.Public | TypeAttributes.Class | TypeAttributes.AutoClass | TypeAttributes.AnsiClass | TypeAttributes.BeforeFieldInit | TypeAttributes.AutoLayout, | |
null); | |
return _uniqueNameTypes[name] = typeBuilder.CreateType(); | |
} | |
private static Type UniqueType<TService>(string name) | |
{ | |
lock (_locker) // there's probably a better way but bah | |
{ | |
if (!_uniqueNames.TryGetValue(name, out var uniqueName)) | |
uniqueName = _uniqueNames[name] = Guid.NewGuid().ToString("N"); | |
if (_uniqueTypes.TryGetValue(uniqueName, out var uniqueType)) | |
return uniqueType; | |
return _uniqueTypes[name] = typeof(W<,>).MakeGenericType(typeof(TService), UniqueType(uniqueName)); | |
} | |
} | |
private static object Create<TImplementation>(IServiceProvider provider, Type type) | |
{ | |
var implementation = ActivatorUtilities.CreateInstance<TImplementation>(provider); | |
var ctor = type.GetConstructors().First(); | |
return ctor.Invoke(new object[] { implementation }); | |
} | |
public static void AddNamedService<TService, TImplementation>(this IServiceCollection serviceCollection, string name, ServiceLifetime lifetime = ServiceLifetime.Transient) | |
where TService : class | |
{ | |
var type = UniqueType<TService>(name); | |
serviceCollection.Add(new ServiceDescriptor(type, provider => Create<TImplementation>(provider, type), lifetime)); | |
} | |
public static TService GetNamedService<TService>(this IServiceProvider serviceProvider, string name) | |
where TService : class | |
{ | |
return ((W<TService>)serviceProvider.GetService(UniqueType<TService>(name))).Service; | |
} | |
} | |
public class W<TService> : IDisposable | |
where TService : class | |
{ | |
public W(TService service) | |
{ | |
Service = service; | |
} | |
public TService Service { get; } | |
public void Dispose() | |
{ | |
if (Service is IDisposable disposable) | |
disposable.Dispose(); | |
} | |
} | |
public class W<TService, TName> : W<TService> | |
where TService : class | |
{ | |
public W(TService service) | |
: base(service) | |
{ } | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment