Search code examples
c#autofacioc-containerdryioc

Covariant service resolution by IoC container


I'm using dependency injection pattern for my application without any IoC Container. Now I decided to use some IoC Container because my Composition Root consists of thousands lines of code, but I failed to make it work with my classes, which actively use variance. For example the following interface

public interface IQuery<in TIn, out TOut>
{
    IReadOnlyCollection<TOut> Get(TIn key);
}

and service

public class FakeRepository : IQuery<object, string>
{
    public IReadOnlyCollection<string> Get(object key)
    {
        return new[] { key.ToString() };
    }
}

Pure DI works fine

IQuery<string, object> service = new FakeRepository();

But neither Autofac nor DryIoc can resolve it.

service = autofacContainer.Resolve<IQuery<string, object>>(); // exception
service = dryIocContainer.Resolve<IQuery<string, object>>(); // exception

Do I need some additional setup? Is there any other IoC container that support this? Am I asking too much?

The full code: https://dotnetfiddle.net/vlw17R


Solution

  • It won't work in current DryIoc versions (stable v2.12.6 and preview v3.0.0-preview-03).

    But nothing in theory prevents the registering of open-generic service type with closed or non-generic implementation type.

    For the single service-to-implementation registration:

    container.Register(typeof(IQuery<,>), typeof(FakeRepository));
    

    DryIoc will throw the exception because of the internal check for implemented types. If I adjust the check to include open-generic version of service type, then this works:

    container.Resolve<IQuery<string, object>>();
    

    The similar adjustment may be done to include open-generic service types in RegisterMany.

    But the remaining issue will be with ResolveMany. It is rather an implementation detail, but having both closed and open-generic versions of services may produce two instances when resolving a collection.

    Concluding, I have created an issue in DryIoc tracker, and will think how to enable this in a safe manner.

    Update

    The new DryIoc v2.12.7 is released with Register capable of registering the open-generic service type. But not the RegisterMany. Check the issue for more details.