Skip to content

Commit 82f60e6

Browse files
committed
Ensure that we only map open generic types that are assignable to the requested service
1 parent 476a36a commit 82f60e6

File tree

2 files changed

+60
-7
lines changed

2 files changed

+60
-7
lines changed

src/LightInject.Tests/OpenGenericTests.cs

Lines changed: 51 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System;
2+
using System.Reflection;
23
using LightInject.SampleLibrary;
34
using Xunit;
45

@@ -10,7 +11,7 @@ public class OpenGenericTests : TestBase
1011
public void GetInstance_PartiallyClosedGeneric_ReturnsInstance()
1112
{
1213
var container = CreateContainer();
13-
container.Register(typeof (IFoo<,>), typeof (HalfClosedFoo<>));
14+
container.Register(typeof(IFoo<,>), typeof(HalfClosedFoo<>));
1415

1516
var instance = container.GetInstance<IFoo<string, int>>();
1617

@@ -43,9 +44,9 @@ public void GetInstance_PartiallyClosedGenericWithDoubleNestedArgument_ReturnsIn
4344
public void GetInstance_PartialClosedAbstractClass_ReturnsInstance()
4445
{
4546
var container = CreateContainer();
46-
container.Register(typeof (Foo<,>), typeof (HalfClosedFooInhertingFromBaseClass<>));
47+
container.Register(typeof(Foo<,>), typeof(HalfClosedFooInhertingFromBaseClass<>));
4748

48-
var instance = container.GetInstance<Foo<string,int>>();
49+
var instance = container.GetInstance<Foo<string, int>>();
4950

5051
Assert.IsType<HalfClosedFooInhertingFromBaseClass<int>>(instance);
5152
}
@@ -54,7 +55,7 @@ public void GetInstance_PartialClosedAbstractClass_ReturnsInstance()
5455
public void GetInstance_ConcreteClass_ReturnsInstance()
5556
{
5657
var container = CreateContainer();
57-
container.Register(typeof (Foo<>));
58+
container.Register(typeof(Foo<>));
5859

5960
var instance = container.GetInstance<Foo<int>>();
6061

@@ -84,9 +85,9 @@ public void GetInstance_NamedServiceWithInvalidConstraint_ThrowsException()
8485
[Fact]
8586
public void GetInstance_NoMatchingOpenGeneric_ThrowsException()
8687
{
87-
var container = CreateContainer();
88+
var container = CreateContainer();
8889

89-
Assert.Throws<InvalidOperationException>(() => container.GetInstance<IFoo<int>>());
90+
Assert.Throws<InvalidOperationException>(() => container.GetInstance<IFoo<int>>());
9091

9192
}
9293

@@ -101,5 +102,49 @@ public void GetInstance_NamedOpenGenerics_IgnoresCaseOnServiceNames()
101102

102103
Assert.IsType<Foo<int>>(instance);
103104
}
105+
106+
[Fact]
107+
public void ShouldMapNestGenericArguments()
108+
{
109+
var container = CreateContainer();
110+
111+
container.Register(typeof(IHandler<>), typeof(Handler<>), "Handler");
112+
container.Register(typeof(IHandler<>), typeof(AnotherHandler<>), "AnotherHandler");
113+
114+
var handlerInstance = container.GetInstance<IHandler<Message<string>>>();
115+
Assert.IsType<Handler<string>>(handlerInstance);
116+
var anotherHandlerInstance = container.GetInstance<IHandler<AnotherMessage<string>>>();
117+
Assert.IsType<AnotherHandler<string>>(anotherHandlerInstance);
118+
}
119+
}
120+
121+
public interface IHandler<TCommand>
122+
{
123+
}
124+
125+
public class Message<TMessage>
126+
{
127+
128+
}
129+
130+
public class AnotherMessage<TAnotherMessage>
131+
{
132+
133+
}
134+
135+
public class Handler<TCommand> : IHandler<Message<TCommand>>
136+
{
137+
public Handler()
138+
{
139+
140+
}
141+
}
142+
143+
public class AnotherHandler<TCommand> : IHandler<AnotherMessage<TCommand>>
144+
{
145+
public AnotherHandler()
146+
{
147+
148+
}
104149
}
105150
}

src/LightInject/LightInject.cs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4484,9 +4484,14 @@ private Action<IEmitter> CreateEmitMethodBasedOnClosedGenericServiceRequest(Type
44844484
foreach (var openGenericServiceRegistration in openGenericServiceRegistrations.Values)
44854485
{
44864486
var closedGenericImplementingTypeCandidate = GenericArgumentMapper.TryMakeGenericType(closedGenericServiceType, openGenericServiceRegistration.ImplementingType);
4487+
44874488
if (closedGenericImplementingTypeCandidate != null)
44884489
{
4489-
candidates.Add(openGenericServiceRegistration.ServiceName, new ClosedGenericCandidate(closedGenericImplementingTypeCandidate, openGenericServiceRegistration.Lifetime));
4490+
// Ensure that we only add candidates that are assignable to the requested service type.
4491+
if (closedGenericServiceType.IsAssignableFrom(closedGenericImplementingTypeCandidate))
4492+
{
4493+
candidates.Add(openGenericServiceRegistration.ServiceName, new ClosedGenericCandidate(closedGenericImplementingTypeCandidate, openGenericServiceRegistration.Lifetime));
4494+
}
44904495
}
44914496
}
44924497

@@ -7171,6 +7176,9 @@ public class GenericArgumentMapper : IGenericArgumentMapper
71717176
/// <returns>A <see cref="GenericMappingResult"/>.</returns>
71727177
public GenericMappingResult Map(Type genericServiceType, Type openGenericImplementingType)
71737178
{
7179+
// string[] genericParameterNames = GetGenericArgumentsOrParameters(genericServiceType).Select(t => t.Name).ToArray();
7180+
7181+
71747182
string[] genericParameterNames =
71757183
openGenericImplementingType.GetTypeInfo().GenericTypeParameters.Select(t => t.Name).ToArray();
71767184

0 commit comments

Comments
 (0)