ZENIT
ZENIT

Reputation: 510

Registring Concrete Types That Implement Variant Generic Interfaces With Autofac

Consider following strucure as a registration subject with Autofac 3.0.0:

class Something
{
    public int Result { get; set; }
}

class SomethingGood : Something
{
    private int _good;
    public int GoodResult {
        get { return _good + Result; }
        set { _good = value; }
    }
}

interface IDo<in T> where T : Something
{
    int Calculate( T input );
}

class MakeSomethingGood : IDo<SomethingGood>
{
    public int Calculate( SomethingGood input ) {
        return input.GoodResult;
    }
}

class ControlSomething
{
    private readonly IDo<Something> _doer;
    public ControlSomething( IDo<Something> doer ) {
        _doer = doer;
    }

    public void Show() {
        Console.WriteLine( _doer.Calculate( new Something { Result = 5 } ) );
    }
}

I'm trying to register concrete type MakeSomethingGood and then resolve it by contravariant interface.

var builder = new ContainerBuilder();
builder.Register( c => new MakeSomethingGood() ).As<IDo<SomethingGood>>();
builder.Register( c => new ControlSomething( c.Resolve<IDo<Something>>() ) ).AsSelf();

var container = builder.Build();
var controller = container.Resolve<ControlSomething>();

... and Resolve fails because no components found for IDo<Something>

What am I doing wrong?

Thank you

Upvotes: 3

Views: 1084

Answers (1)

Steven
Steven

Reputation: 172835

You register an IDo<SomethingGood> and try to resolve an IDo<Something>. How is that ever supposed to work? For this to work, IDo<T> should be defined as covariant: IDo<out T>.

Since IDo<in T> is defined as contravariant (using the in keyword), you can't simply assign an IDo<SomethingGood> to IDo<Something>. This won't compile in C#:

IDo<SomethingGood> good = new MakeSomethingGood();

// Won't compile
IDo<Something> some = good;

And that's why Autofac can't resolve it, even with the ContravariantRegistrationSource.

Upvotes: 1

Related Questions