Autofac 注册所有名为 IFoo.Name 的 IFoo 类型

Autofac register all of type IFoo named IFoo.Name

刚刚学习 Autofac 并努力按照惯例注册一些命名实例。

public interface IFoo
{
    string AutoFactName{ get; }
    object DoSomething();
}

看看这个界面,我想要完成的是这些方面的东西

        builder.RegisterTypes()
            .AssignableTo<IFoo>()
            .As<IFoo>()
            .Named<IFoo>(i => i.AutoFactName);

我已经尝试了一些变体来达到这种效果。 最终目标是动态注册和解析实例。

您不需要实例来在 Autofac 中注册您的类型。如果你需要来自你的类型的信息,最好使用像 Attribute 这样的元信息。类似的东西:

[FooMetadata("Foo1")]
public class Foo1 : IFoo 
{ }

然后在注册时使用此元数据

builder.RegisterAssemblyTypes(assembly)
        .AssignableTo<IFoo>()
        .Named<IFoo>(t => t.GetCustomAttribute<FooMetadata>().Foo);

如果您需要在您的实例中获取命名类型,您可以使用 IRegistrationSource

public class NamedFooRegistrationSource : IRegistrationSource
{
    public bool IsAdapterForIndividualComponents => false;

    public IEnumerable<IComponentRegistration> RegistrationsFor(
        Service service,
        Func<Service, IEnumerable<IComponentRegistration>> registrationAccessor)
    {

        KeyedService keyedService = service as KeyedService;

        if (keyedService == null || keyedService.ServiceKey.GetType() != typeof(String))
        {
            yield break;
        }

        IComponentRegistration registration = RegistrationBuilder
            .ForDelegate(keyedService.ServiceType, (c, p) =>
            {
                Type foosType = typeof(IEnumerable<>).MakeGenericType(keyedService.ServiceType);
                IEnumerable<IFoo> foos = (IEnumerable<IFoo>)c.Resolve(foosType);

                foos = foos.Where(f => f.AutoFactName == (String)keyedService.ServiceKey).ToArray();
                if (foos.Count() == 0)
                {
                    throw new Exception($"no Foo available for {keyedService.ServiceKey}");
                }
                else if (foos.Count() > 1)
                {
                    throw new Exception($"more than 1 Foo available for {keyedService.ServiceKey}");
                }
                else
                {
                    return foos.First();
                }
            })
            .Named((String)keyedService.ServiceKey, keyedService.ServiceType)
            .CreateRegistration();

        yield return registration;
    }
}

然后以这种方式注册您的Foo

builder.RegisterAssemblyTypes(assembly)
        .AssignableTo<IFoo>()
        .As<IFoo>();
builder.RegisterSource<NamedFooRegistrationSource>();