- 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. 43
      Test.LightweightIocContainer/OpenGenericRegistrationTest.cs

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

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

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

@ -20,6 +20,9 @@ public class OpenGenericRegistrationTest
[UsedImplicitly]
public class Constraint : IConstraint;
[UsedImplicitly]
public class AnotherConstraint : IConstraint;
[UsedImplicitly]
[SuppressMessage("ReSharper", "UnusedTypeParameter")]
@ -50,15 +53,27 @@ public class OpenGenericRegistrationTest
}
[UsedImplicitly]
public interface IA;
public interface IA
{
ITest<Constraint> Test { get; }
}
[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]
@ -126,4 +141,20 @@ public class OpenGenericRegistrationTest
IA a = _iocContainer.Resolve<IA>();
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