简体   繁体   中英

Resolve all classes that annotated with Attribute as IEnumerable<Type> using Autofac

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> .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM