- fix openGeneric type registered as singleton not being handled correctly

master
Simon G. 12 months ago
parent d0e5c4f307
commit f5c5c26147
Signed by: SimonG
GPG Key ID: 0B82B964BA536523
  1. 2
      LightweightIocContainer/Interfaces/Registrations/IOpenGenericRegistration.cs
  2. 29
      LightweightIocContainer/IocContainer.cs
  3. 2
      LightweightIocContainer/Registrations/OpenGenericRegistration.cs
  4. 39
      Test.LightweightIocContainer/OpenGenericRegistrationTest.cs

@ -9,5 +9,5 @@ namespace LightweightIocContainer.Interfaces.Registrations;
/// </summary> /// </summary>
public interface IOpenGenericRegistration : ITypedRegistration public interface IOpenGenericRegistration : ITypedRegistration
{ {
internal Type CreateGenericImplementationType<T>();
} }

@ -235,10 +235,7 @@ public class IocContainer : IIocContainer, IIocResolver
switch (result) switch (result)
{ {
case true when registration is IOpenGenericRegistration openGenericRegistration: case true when registration is IOpenGenericRegistration openGenericRegistration:
{ return (true, new InternalToBeResolvedPlaceholder(openGenericRegistration.CreateGenericImplementationType<T>(), registration, parametersToResolve), null);
Type genericImplementationType = openGenericRegistration.ImplementationType.MakeGenericType(typeof(T).GenericTypeArguments);
return (true, new InternalToBeResolvedPlaceholder(genericImplementationType, registration, parametersToResolve), null);
}
case true: case true:
return (true, new InternalToBeResolvedPlaceholder(registeredType, registration, parametersToResolve), null); return (true, new InternalToBeResolvedPlaceholder(registeredType, registration, parametersToResolve), null);
} }
@ -383,21 +380,16 @@ public class IocContainer : IIocContainer, IIocResolver
/// <returns>A newly created instance of the given <see cref="Type"/></returns> /// <returns>A newly created instance of the given <see cref="Type"/></returns>
private T CreateInstance<T>(IRegistration registration, object?[]? arguments) private T CreateInstance<T>(IRegistration registration, object?[]? arguments)
{ {
T instance; T instance = registration switch
if (registration is IOpenGenericRegistration openGenericRegistration)
{ {
//create generic implementation type from generic arguments of T IOpenGenericRegistration openGenericRegistration => Creator.CreateInstance<T>(openGenericRegistration.CreateGenericImplementationType<T>(), arguments),
Type genericImplementationType = openGenericRegistration.ImplementationType.MakeGenericType(typeof(T).GenericTypeArguments); ISingleTypeRegistration<T> singleTypeRegistration => singleTypeRegistration.FactoryMethod == null
instance = Creator.CreateInstance<T>(genericImplementationType, arguments); ? Creator.CreateInstance<T>(singleTypeRegistration.InterfaceType, arguments)
} : singleTypeRegistration.FactoryMethod(this),
else if (registration is ISingleTypeRegistration<T> singleTypeRegistration) ILifestyleProvider { Lifestyle: Lifestyle.Multiton } and IMultitonRegistration multitonRegistration => CreateMultitonInstance<T>(multitonRegistration, arguments),
instance = singleTypeRegistration.FactoryMethod == null ? Creator.CreateInstance<T>(singleTypeRegistration.InterfaceType, arguments) : singleTypeRegistration.FactoryMethod(this); ITypedRegistration defaultRegistration => Creator.CreateInstance<T>(defaultRegistration.ImplementationType, arguments),
else if (registration is ILifestyleProvider { Lifestyle: Lifestyle.Multiton } and IMultitonRegistration multitonRegistration) _ => throw new UnknownRegistrationException($"There is no registration of type {registration.GetType().Name}.")
instance = CreateMultitonInstance<T>(multitonRegistration, arguments); };
else if (registration is ITypedRegistration defaultRegistration)
instance = Creator.CreateInstance<T>(defaultRegistration.ImplementationType, arguments);
else
throw new UnknownRegistrationException($"There is no registration of type {registration.GetType().Name}.");
if (registration is ILifestyleProvider { Lifestyle: Lifestyle.Singleton }) if (registration is ILifestyleProvider { Lifestyle: Lifestyle.Singleton })
_singletons.TryAdd(GetType<T>(registration), instance); _singletons.TryAdd(GetType<T>(registration), instance);
@ -741,6 +733,7 @@ public class IocContainer : IIocContainer, IIocResolver
private Type GetType<T>(IRegistration registration) => private Type GetType<T>(IRegistration registration) =>
registration switch registration switch
{ {
IOpenGenericRegistration openGenericRegistration => openGenericRegistration.CreateGenericImplementationType<T>(),
ITypedRegistration typedRegistration => typedRegistration.ImplementationType, ITypedRegistration typedRegistration => typedRegistration.ImplementationType,
ISingleTypeRegistration<T> singleTypeRegistration => singleTypeRegistration.InterfaceType, ISingleTypeRegistration<T> singleTypeRegistration => singleTypeRegistration.InterfaceType,
_ => throw new UnknownRegistrationException($"Unknown registration used: {registration.GetType().Name}.") _ => throw new UnknownRegistrationException($"Unknown registration used: {registration.GetType().Name}.")

@ -29,6 +29,8 @@ internal class OpenGenericRegistration : RegistrationBase, IOpenGenericRegistrat
/// </summary> /// </summary>
public Type ImplementationType { get; } public Type ImplementationType { get; }
public Type CreateGenericImplementationType<T>() => ImplementationType.MakeGenericType(typeof(T).GenericTypeArguments);
/// <summary> /// <summary>
/// Validate this <see cref="OpenGenericRegistration"/> /// Validate this <see cref="OpenGenericRegistration"/>
/// </summary> /// </summary>

@ -21,6 +21,9 @@ public class OpenGenericRegistrationTest
[UsedImplicitly] [UsedImplicitly]
public class Constraint : IConstraint; public class Constraint : IConstraint;
[UsedImplicitly]
public class AnotherConstraint : IConstraint;
[UsedImplicitly] [UsedImplicitly]
[SuppressMessage("ReSharper", "UnusedTypeParameter")] [SuppressMessage("ReSharper", "UnusedTypeParameter")]
public interface ITest<T> where T : IConstraint, new(); public interface ITest<T> where T : IConstraint, new();
@ -50,15 +53,27 @@ public class OpenGenericRegistrationTest
} }
[UsedImplicitly] [UsedImplicitly]
public interface IA; public interface IA
{
ITest<Constraint> Test { get; }
}
[UsedImplicitly] [UsedImplicitly]
public class A : IA public class A(ITest<Constraint> test) : IA
{
public A(ITest<Constraint> test)
{ {
public ITest<Constraint> Test { get; } = test;
}
[UsedImplicitly]
public interface IB
{
ITest<AnotherConstraint> Test { get; }
} }
[UsedImplicitly]
public class B(ITest<AnotherConstraint> test) : IB
{
public ITest<AnotherConstraint> Test { get; } = test;
} }
[SetUp] [SetUp]
@ -126,4 +141,20 @@ public class OpenGenericRegistrationTest
IA a = _iocContainer.Resolve<IA>(); IA a = _iocContainer.Resolve<IA>();
Assert.That(a, Is.TypeOf<A>()); Assert.That(a, Is.TypeOf<A>());
} }
[Test]
public void TestOpenGenericTypeAsParameterDifferentGenericParametersResolveDifferentSingletons()
{
_iocContainer.Register(r => r.Add<IA, A>());
_iocContainer.Register(r => r.Add<IB, B>());
_iocContainer.Register(r => r.AddOpenGenerics(typeof(ITest<>), typeof(Test<>), Lifestyle.Singleton));
IA a = _iocContainer.Resolve<IA>();
Assert.That(a, Is.TypeOf<A>());
IB b = _iocContainer.Resolve<IB>();
Assert.That(b, Is.TypeOf<B>());
Assert.That(b.Test, Is.Not.SameAs(a.Test));
}
} }
Loading…
Cancel
Save