I have 3 classes annotated with Attribute
[MyAttribute("xyz")]
class Class1
{}
//... other classes annotated with MyAttribute
I registered all types
IContainer container ;
var builder = new ContainerBuilder();
//register all types annotated by MyAttribute
Assembly assembly = Assembly.GetExecutingAssembly();
builder.RegisterAssemblyTypes(assembly)
.Where(t => t.GetCustomAttribute<MyAttribute>() != null);
//other registered classes /services
container = builder.Build();
Try to resolve:
//what this line(s) can be for only class that annotated by attribute
IEnumerable<Type> types = container.Resolve<IEnumerable<Type>>();
This answer didn't help
How to resolve and get IEnumerable<Type>
When you do this:
builder.RegisterAssemblyTypes(assembly)
.Where(t => t.GetCustomAttribute<MyAttribute>() != null);
Under the covers it's basically doing this:
var types = assembly.GetTypes().Where(t => t.GetCustomAttribute<MyAttribute>() != null)
foreach(var type in types)
{
builder.RegisterType(type).AsSelf();
}
Let's say you had three types with the attribute: MyClass1
, MyClass2
, MyClass3
. That means the registration would basically be the same as:
builder.RegisterType<MyClass1>();
builder.RegisterType<MyClass2>();
builder.RegisterType<MyClass3>();
At no point in there are you registering the type Type
with Autofac.
Honestly, I'd recommend against registering super generic base types like string
or Type
with Autofac anyway. I'd create a factory that gets the information. That way if I ever need to have two different lists of Type
then I could separate them easily by using two different factory interfaces.
But let's say you want to do that anyway, you actually have to register Type
not MyClass1
or whatever. Autofac doesn't do that sort of thing out of the box. You will have to do it yourself.
I don't have this running through a compiler, but it should be something like...
var types = assembly.GetTypes().Where(t => t.GetCustomAttribute<MyAttribute>() != null)
foreach(var type in types)
{
builder.RegisterInstance(type).As<Type>();
}
The idea is that you want the Type
registered so you can list those things, not that you're trying to instantiate the things you located. You don't want to RegisterType(type)
because that means, basically, that you want Autofac to be able to create an instance of type
, not track the list of those types so you can get them later. This sort of confusion is another great reason to put this behind a factory of your own creation.
Really simply:
public class TypeFactory
{
public IEnumerable<Type> Types {get;}
public TypeFactory(IEnumerable<Type> types)
{
this.Types = types;
}
}
Then:
var types = assembly.GetTypes().Where(t => t.GetCustomAttribute<MyAttribute>() != null)
var factory = new TypeFactory(types);
builder.RegisterInstance(factory);
Then resolve TypeFactory
instead of trying to resolve directly an IEnumerable<Type>
.