14

I have a base class, and a series of other classes inheriting from this:
(Please excuse the over-used animal analogy)

public abstract class Animal { }

public class Dog : Animal { }

public class Cat : Animal { }

I then have a class that has a dependancy on an IEnumerable<Animal>

public class AnimalFeeder
{
    private readonly IEnumerable<Animal> _animals;

    public AnimalFeeder(IEnumerable<Animal> animals )
    {
        _animals = animals;
    }
}

If I manually do something like this:

var animals =
    typeof(Animal).Assembly.GetTypes()
        .Where(x => x.IsSubclassOf(typeof(Animal)))
        .ToList();

Then I can see that this returns Dog and Cat

However, when I try to wire up my Autofac like this:

builder.RegisterAssemblyTypes(typeof(Animal).Assembly)
    .Where(t => t.IsSubclassOf(typeof(Animal)));

builder.RegisterType<AnimalFeeder>();

When AnimalFeeder is instantiated, there are no Animal passed in to the constructor.

Have I missed something?

Alex
  • 37,502
  • 51
  • 204
  • 332
  • 3
    You are probably missing the `As()` in your registartion: `builder.RegisterAssemblyTypes(typeof(Animal).Assembly) .Where(t => t.IsSubclassOf(typeof(Animal))).As();` – nemesv Dec 04 '13 at 10:38
  • 1
    Might want to convert that comment to an answer! ;-) Thanks – Alex Dec 04 '13 at 10:48

1 Answers1

26

You are missing the As<Animal>() call in your registration.

Without it Autofac will register your types with the default AsSelf() setting so you won't get your classes if you ask for base type with IEnumerable<Animal> only if you use the sub-types like Dog and Cat.

So change your registration to:

builder.RegisterAssemblyTypes(typeof(Animal).Assembly)
     .Where(t => t.IsSubclassOf(typeof(Animal)))
     .As<Animal>();
nemesv
  • 138,284
  • 16
  • 416
  • 359
  • 1
    I know this question is old but what if you want to register a named subclass of the abstract class? – Cizaphil Jun 16 '16 at 05:21
  • 2
    Named registrations can be also resolved with `IEnumarable` when they are registered with the type **and** the name. So `builder.RegisterType().As().Named("Dog"); builder.RegisterType().As().Named("Cat");` in this case `IEnumerable` will return both, but you can also resolve the individual ones with: `container.ResolveNamed("Dog");`. You can even combine it with the assembly scanning: `builder.RegisterAssemblyTypes(...).As();` and then register your named ones additionally: `builder.RegisterType().Named("Dog");` – nemesv Jun 16 '16 at 05:52
  • 1
    @nemesv: I was able to [get mine working](https://stackoverflow.com/q/75845890) using your great tip here in the comments. Would you make this an answer over there so I can accept it? My final syntax: `oBuilder.RegisterType(Of CleanCommand).As(Of IBaseCommand).Named(Of BaseCommand)(NameOf(CleanCommand)).WithParameters(oParameters)` and `oCleanCommand = oScope.ResolveNamed(Of BaseCommand)(NameOf(CleanCommand))`, `oDownloader = oScope.Resolve(Of IDownloader)`. – InteXX Mar 26 '23 at 13:54
  • 1
    @nemesv: p.s. I don't mind if the answer is in C#. In fact I prefer it, if that's easier for you. – InteXX Mar 26 '23 at 14:03