This repository was archived by the owner on Nov 2, 2018. It is now read-only.
This repository was archived by the owner on Nov 2, 2018. It is now read-only.
Mixing open generic and closed types for IEnumerable<T> #500
Closed
Description
Hi Team,
I'm having trouble getting a particular scenario to work. I want to resolve all instances of a closed generic type, where the registrations may contain both concrete and open registrations:
public interface IHandler<TRequest, TResponse>
{
TResponse Handle(TRequest request);
}
public class OpenHandler<TRequest, TResponse> : IHandler<TRequest, TResponse>
{
public TResponse Handle(TRequest request)
{
return default(TResponse);
}
}
public class ClosedHandler : IHandler<string, int>
{
public int Handle(string request)
{
return int.Parse(request);
}
}
When I try and resolve all instances of IHandler<string, int>
, only the concrete implementation is returned:
var services = new ServiceCollection();
services.AddTransient<IHandler<string, int>, ClosedHandler>();
services.AddTransient(typeof(IHandler<,>), typeof(OpenHandler<,>));
var provider = services.BuildServiceProvider();
var handlers = provider.GetServices<IHandler<string, int>>().ToArray(); // Only 1 item - ClosedHandler
I thought I'd test other containers to see what they do:
class Program
{
static void Main(string[] args)
{
#region Stock
{
var services = new ServiceCollection();
services.AddTransient<IHandler<string, int>, ClosedHandler>();
services.AddTransient(typeof(IHandler<,>), typeof(OpenHandler<,>));
var provider = services.BuildServiceProvider();
var handlers = provider.GetServices<IHandler<string, int>>().ToArray(); // Returns 1
}
#endregion
#region StructureMap
{
var container = new StructureMap.Container(c =>
{
c.For<IHandler<string, int>>().Use<ClosedHandler>();
c.For(typeof(IHandler<,>)).Use(typeof(OpenHandler<,>));
});
var handlers = container.GetAllInstances<IHandler<string, int>>().ToArray(); // Returns 1
}
#endregion
#region Autofac
{
var builder = new Autofac.ContainerBuilder();
builder.RegisterType<ClosedHandler>().As<IHandler<string, int>>().InstancePerLifetimeScope();
builder.RegisterGeneric(typeof(OpenHandler<,>)).As(typeof(IHandler<,>)).InstancePerLifetimeScope();
var container = builder.Build();
var handlers = container.Resolve<IEnumerable<IHandler<string, int>>>().ToArray(); // Returns 2
}
#endregion
#region Ninject
{
var kernel = new Ninject.StandardKernel();
kernel.Bind<IHandler<string, int>>().To<ClosedHandler>();
kernel.Bind(typeof(IHandler<,>)).To(typeof(OpenHandler<,>));
var handlers = kernel.GetAll<IHandler<string, int>>().ToArray(); // Returns 2
}
#endregion
#region SimpleInjector
{
var container = new SimpleInjector.Container();
container.RegisterCollection(typeof(IHandler<,>), new[]
{
typeof(ClosedHandler),
typeof(OpenHandler<,>)
});
var handlers = container.GetAllInstances<IHandler<string, int>>().ToArray(); // Returns 2
}
#endregion
}
}
Here is my project file:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp1.1</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Autofac" Version="4.4.0" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="1.1.0" />
<PackageReference Include="Ninject" Version="4.0.0-beta-0134" />
<PackageReference Include="SimpleInjector" Version="4.0.0-beta1" />
<PackageReference Include="StructureMap" Version="4.4.3" />
</ItemGroup>
</Project>
In all but Microsoft.Extensions.DependencyInjection
and StructureMap, all other contains return both instances.
What would your recommendation be to achieve this? Is this functionality missing?