Playing with CommonServiceLocator

This commit is contained in:
Holger Börchers 2019-07-28 15:01:39 +02:00
parent 3a45db0d77
commit 800a06fc5a
6 changed files with 88 additions and 22 deletions

View File

@ -1,5 +1,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
namespace SmallInjector namespace SmallInjector
{ {
@ -8,13 +9,21 @@ namespace SmallInjector
/// </summary> /// </summary>
public class Container : IContainer public class Container : IContainer
{ {
private readonly Dictionary<Type, RegisteredType> _container = new Dictionary<Type, RegisteredType>(); private readonly Dictionary<Type, List<RegisteredType>> _container = new Dictionary<Type, List<RegisteredType>>();
/// <inheritdoc/> /// <inheritdoc/>
public void RegisterType<TService, TInterface>(bool isSingleton, TService instance = default) public void RegisterType<TService, TInterface>(bool isSingleton, TService instance = default)
where TService : TInterface where TService : TInterface
{ {
_container.Add(typeof(TInterface), new RegisteredType(typeof(TService), isSingleton, null)); if (!IsRegistered<TService>())
{
_container[typeof(TInterface)] = new List<RegisteredType>
{new RegisteredType(typeof(TService), isSingleton, null)};
}
else
{
_container[typeof(TInterface)].Add(new RegisteredType(typeof(TService), isSingleton, null));
}
} }
/// <inheritdoc/> /// <inheritdoc/>
@ -30,26 +39,38 @@ namespace SmallInjector
/// <inheritdoc /> /// <inheritdoc />
public bool IsRegistered(Type serviceType) => _container.ContainsKey(serviceType); public bool IsRegistered(Type serviceType) => _container.ContainsKey(serviceType);
/// <inheritdoc/> /// <inheritdoc />
public object Resolve(Type serviceInterface) public IEnumerable<object> ResolveAny(Type serviceType)
{ {
if (!_container.TryGetValue(serviceInterface, out var registeredType)) if (!_container.TryGetValue(serviceType, out var registeredTypes))
throw new Exception(@"Dependency {serviceInterface} is not registered"); throw new Exception(@"Dependency {serviceType} is not registered");
foreach (var registeredType in registeredTypes)
if (registeredType.IsSingleton && registeredType.Instance != null)
return registeredType.Instance;
var constructor = registeredType.ServiceType.GetConstructors()[0];
var parameters = constructor.GetParameters();
var constructorParameters = new object[parameters.Length];
for (var i = 0; i < parameters.Length; i++)
{ {
constructorParameters[i] = Resolve(parameters[i].ParameterType); if (registeredType.IsSingleton && registeredType.Instance != null)
} {
yield return registeredType.Instance;
continue;
}
var instance = constructor.Invoke(constructorParameters); var constructor = registeredType.ServiceType.GetConstructors()[0];
return registeredType.IsSingleton ? (registeredType.Instance = instance) : instance; var parameters = constructor.GetParameters();
var constructorParameters = new object[parameters.Length];
for (var i = 0; i < parameters.Length; i++)
{
constructorParameters[i] = Resolve(parameters[i].ParameterType);
}
var instance = constructor.Invoke(constructorParameters);
yield return registeredType.IsSingleton ? (registeredType.Instance = instance) : instance;
}
} }
/// <inheritdoc />
public IEnumerable<object> ResolveAny<TService>() => ResolveAny(typeof(TService));
/// <inheritdoc/>
public object Resolve(Type serviceType) => ResolveAny(serviceType).First();
private class RegisteredType private class RegisteredType
{ {
public bool IsSingleton { get; } public bool IsSingleton { get; }

View File

@ -1,4 +1,5 @@
using System; using System;
using System.Collections.Generic;
namespace SmallInjector namespace SmallInjector
{ {
@ -24,7 +25,7 @@ namespace SmallInjector
/// <summary> /// <summary>
/// Resolve service of specified type. /// Resolve service of specified type.
/// </summary> /// </summary>
object Resolve(Type serviceInterface); object Resolve(Type serviceType);
/// <summary> /// <summary>
/// Resolve service of specified type. /// Resolve service of specified type.
@ -40,5 +41,8 @@ namespace SmallInjector
/// Returns true, if the service is registered. False otherwise. /// Returns true, if the service is registered. False otherwise.
/// </summary> /// </summary>
bool IsRegistered(Type serviceType); bool IsRegistered(Type serviceType);
IEnumerable<object> ResolveAny(Type serviceType);
IEnumerable<object> ResolveAny<TService>();
} }
} }

View File

@ -0,0 +1,27 @@
using System;
using System.Collections.Generic;
namespace SmallInjector
{
/// <summary>
/// Wrapper for Service Locator
/// </summary>
public class ServiceLocatorWrapper : CommonServiceLocator.ServiceLocatorImplBase
{
private readonly IContainer _container;
/// <summary>
/// Creates new <see cref="ServiceLocatorWrapper"/> instance
/// </summary>
public ServiceLocatorWrapper(IContainer container)
{
_container = container;
}
/// <inheritdoc />
protected override object DoGetInstance(Type serviceType, string key) => _container.Resolve(serviceType);
/// <inheritdoc />
protected override IEnumerable<object> DoGetAllInstances(Type serviceType) => _container.ResolveAny(serviceType);
}
}

View File

@ -12,4 +12,8 @@
<DocumentationFile>C:\Users\Holger\Desktop\SmallInjectorDemo\SmallInjector\SmallInjector.xml</DocumentationFile> <DocumentationFile>C:\Users\Holger\Desktop\SmallInjectorDemo\SmallInjector\SmallInjector.xml</DocumentationFile>
</PropertyGroup> </PropertyGroup>
<ItemGroup>
<PackageReference Include="CommonServiceLocator" Version="2.0.4" />
</ItemGroup>
</Project> </Project>

View File

@ -1,4 +1,5 @@
using System; using System;
using CommonServiceLocator;
using SmallInjector; using SmallInjector;
namespace SmallInjectorDemo namespace SmallInjectorDemo
@ -7,8 +8,11 @@ namespace SmallInjectorDemo
{ {
private static void Main() private static void Main()
{ {
Console.WriteLine("Small dependency injection example");
IContainer container = new Container(); IContainer container = new Container();
ServiceLocator.SetLocatorProvider(() => new ServiceLocatorWrapper(container));
Console.WriteLine("Small dependency injection example");
container.RegisterType(true, container); container.RegisterType(true, container);
Console.WriteLine("Register " + nameof(SystemClock)); Console.WriteLine("Register " + nameof(SystemClock));
container.RegisterType<SystemClock, IClock>(true); container.RegisterType<SystemClock, IClock>(true);
@ -28,9 +32,12 @@ namespace SmallInjectorDemo
Console.WriteLine(); Console.WriteLine();
Console.WriteLine("Resolve class instances:"); Console.WriteLine("Resolve class instances:");
var useful1 = container.Resolve<ServiceConsumer>(); //var useful1 = container.Resolve<ServiceConsumer>();
var useful2 = container.Resolve<ServiceConsumer>(); //var useful2 = container.Resolve<ServiceConsumer>();
var useful3 = container.Resolve<ServiceConsumer>(); //var useful3 = container.Resolve<ServiceConsumer>();
var useful1 = ServiceLocator.Current.GetInstance<ServiceConsumer>();
var useful2 = ServiceLocator.Current.GetInstance<ServiceConsumer>();
var useful3 = ServiceLocator.Current.GetInstance<ServiceConsumer>();
Console.WriteLine(); Console.WriteLine();
Console.WriteLine("Run test methods:"); Console.WriteLine("Run test methods:");
useful1.TestTheServices(); useful1.TestTheServices();

View File

@ -12,6 +12,9 @@
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
<DocumentationFile>bin\Release\netcoreapp2.1\SmallInjectorDemo.xml</DocumentationFile> <DocumentationFile>bin\Release\netcoreapp2.1\SmallInjectorDemo.xml</DocumentationFile>
</PropertyGroup> </PropertyGroup>
<ItemGroup>
<PackageReference Include="CommonServiceLocator" Version="2.0.4" />
</ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\SmallInjector\SmallInjector.csproj" /> <ProjectReference Include="..\SmallInjector\SmallInjector.csproj" />
</ItemGroup> </ItemGroup>