Skip to content

Commit

Permalink
Bug fix: Open-generic registrations for types with generic array gene…
Browse files Browse the repository at this point in the history
…ric type arguments couldn't be resolved Fixes #996
  • Loading branch information
dotnetjunkie committed Apr 25, 2024
1 parent fd9e9b8 commit 59c7205
Show file tree
Hide file tree
Showing 2 changed files with 89 additions and 1 deletion.
69 changes: 69 additions & 0 deletions src/SimpleInjector.Tests.Unit/RegisterOpenGenericTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1348,6 +1348,75 @@ public void Register_OverridingNonConditionalOpenGenericTypeWithNewTypeConstrain
actualInstance: container.GetInstance<INewConstraintedGeneric<int>>());
}

[TestMethod]
public void Verify_ClosedGenericRegistrationOfOpenGenericTypeWithGenericArrayType_Succeeds()
{
var container = new Container();

container.Register<IQueryHandler<GenericArrayQuery<int>, Tuple<int>[]>, GenericArrayQueryHandler<int>>();

container.Register<ServiceDependingOn<IQueryHandler<GenericArrayQuery<int>, Tuple<int>[]>>>();

container.Verify();
}

[TestMethod]
public void Verify_ClosedGenericRegistrationOfOpenGenericTypeWithGenericArrayTypeAfterOtherClosedRegistrationForSameType_Succeeds()
{
var container = new Container();

container.Register<IQueryHandler<SimpleQuery, object>, SimpleQueryHandler>();

container.Register<IQueryHandler<GenericArrayQuery<int>, Tuple<int>[]>, GenericArrayQueryHandler<int>>();

container.Register<ServiceDependingOn<IQueryHandler<GenericArrayQuery<int>, Tuple<int>[]>>>();

container.Verify();
}

[TestMethod]
public void Verify_OpenGenericRegistrationOfOpenGenericTypeWithGenericArrayTypeAfterClosedRegistrationForSameType_Succeeds()
{
var container = new Container();

container.Register<IQueryHandler<SimpleQuery, object>, SimpleQueryHandler>();

container.Register(typeof(IQueryHandler<,>), typeof(GenericArrayQueryHandler<>));

container.Register<ServiceDependingOn<IQueryHandler<GenericArrayQuery<int>, Tuple<int>[]>>>();

container.Verify();
}

[TestMethod]
public void GetInstance_OpenGenericRegistrationOfOpenGenericTypeWithGenericArrayType_Succeeds()
{
var container = new Container();

container.Register(typeof(IQueryHandler<,>), typeof(GenericArrayQueryHandler<>));

container.GetInstance<IQueryHandler<GenericArrayQuery<int>, Tuple<int>[]>>();
}

[TestMethod]
public void GetInstance_OpenGenericRegistrationOfOpenGenericTypeWithGenericEnumerableElementType_Succeeds()
{
var container = new Container();

container.Register(typeof(IQueryHandler<,>), typeof(GenericEnumerableQueryHandler<>));

container.GetInstance<IQueryHandler<GenericEnumerableQuery<int>, IEnumerable<Tuple<int>>>>();
}

public class SimpleQuery : IQuery<object> { }
public class SimpleQueryHandler : IQueryHandler<SimpleQuery, object> { }

public class GenericArrayQuery<T> : IQuery<Tuple<T>[]> { }
public class GenericArrayQueryHandler<T> : IQueryHandler<GenericArrayQuery<T>, Tuple<T>[]> { }

public class GenericEnumerableQuery<T> : IQuery<IEnumerable<Tuple<T>>> { }
public class GenericEnumerableQueryHandler<T> : IQueryHandler<GenericEnumerableQuery<T>, IEnumerable<Tuple<T>>> { }

public interface IService<T> { }

public class ServiceImplementation<T> : IService<T> { }
Expand Down
21 changes: 20 additions & 1 deletion src/SimpleInjector/Internals/GenericArgumentFinder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,9 @@ private ArgumentMapping[] ConvertToOpenImplementationArgumentMappingsRecursive(
return new ArgumentMapping[] { mapping };
}

var argumentTypeDefinition = mapping.Argument.GetGenericTypeDefinition();
var argumentTypeDefinition = mapping.Argument.IsArray
? this.GetGenericArrayDefinition(mapping.Argument)
: mapping.Argument.GetGenericTypeDefinition();

// Try to get mappings for each type in the type hierarchy that is compatible to the argument.
return (
Expand All @@ -183,6 +185,23 @@ from arg in this.ConvertToOpenImplementationArgumentMappingsForType(mapping, typ
.ToArray();
}

private Type GetGenericArrayDefinition(Type type)
{
var elementType = type.GetElementType();

if (elementType.IsArray)
{
elementType = this.GetGenericArrayDefinition(elementType);
}
else if (elementType.IsGenericType())
{
elementType = elementType.GetGenericTypeDefinition();
}

return elementType.MakeArrayType();
}


private ArgumentMapping[] ConvertToOpenImplementationArgumentMappingsForType(
ArgumentMapping mapping, Type type, IList<Type> processedTypes)
{
Expand Down

0 comments on commit 59c7205

Please sign in to comment.