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

wor*_*yte 0 c# dependency-injection autofac autofac-configuration

只是学习Autofac并努力按照惯例重新命名几个命名实例。

public interface IFoo
{
    string AutoFactName{ get; }
    object DoSomething();
}
Run Code Online (Sandbox Code Playgroud)

看着这个界面,我想要完成的是沿着这些思路

        builder.RegisterTypes()
            .AssignableTo<IFoo>()
            .As<IFoo>()
            .Named<IFoo>(i => i.AutoFactName);
Run Code Online (Sandbox Code Playgroud)

我已经尝试了一些实现这种效果的方法。最终目标是动态注册和解析实例。

Cyr*_*and 5

您不需要实例即可在Autofac中注册您的类型。如果您需要输入类型的信息,最好使用元信息,例如Attribute。像这样:

[FooMetadata("Foo1")]
public class Foo1 : IFoo 
{ }
Run Code Online (Sandbox Code Playgroud)

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

builder.RegisterAssemblyTypes(assembly)
        .AssignableTo<IFoo>()
        .Named<IFoo>(t => t.GetCustomAttribute<FooMetadata>().Foo);
Run Code Online (Sandbox Code Playgroud)

如果您需要在实例中获取命名类型,则可以使用 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;
    }
}
Run Code Online (Sandbox Code Playgroud)

然后以Foo这种方式注册:

builder.RegisterAssemblyTypes(assembly)
        .AssignableTo<IFoo>()
        .As<IFoo>();
builder.RegisterSource<NamedFooRegistrationSource>();
Run Code Online (Sandbox Code Playgroud)