带有运行时构造函数参数的键控委托工厂?

Ker*_*rby 16 autofac

可以说我有以下服务和组件:

public interface IService
{
    void DoWork();
}

public class ServiceA : IService
{
    private readonly string _name;

    public ServiceA(string name)
    {
        _name = name;
    }

    public void DoWork()
    {
        //ServiceA DoWork implementation
    }
}

public class ServiceB : IService
{
    private readonly string _name;

    public ServiceB(string name)
    {
        _name = name;
    }

    public void DoWork()
    {
        //ServiceB DoWork implementation
    }
}
Run Code Online (Sandbox Code Playgroud)

请注意,每个组件都使用构造函数参数name.让我们说这name是在运行时确定的.

我一直在浏览AutoFac文档,试图找到一种类型安全的方法来解决这样的组件,而不必直接引用容器.如果我只有一个实现,IService那么我可以使用Delegate Factory将runtime参数传递给构造函数.但是,我有两个实现,并且还应该在运行时确定应该使用的实现.如果我没有name构造函数参数,那么我可以通过Key注册这两个组件,并使用IIndex注册

我无法弄清楚如何做到这两点.有没有办法我能以某种方式结合代表工厂和IIndex组件解决方案的使用?或者是否有另一种方法来注册和解决这两个组件而无需直接引用容器?

Mat*_*ton 10

正如您所说,AutoFac本身支持您的两个单独要求.

但是,似乎没有直接支持将这两种结构一起使用.即以下不起作用:

public enum ServiceType
{
    ServiceA,
    ServiceB
}

public class MyComponent
{
    public MyComponent(Func<string, IIndex<ServiceType, IService> factory)
    {
        var service = factory("some_string")[ServiceType.ServiceA];
    }
}
Run Code Online (Sandbox Code Playgroud)

我的工作一直是将服务的解决方案转移到每个服务实现的工厂.然后按如下方式工作:

  1. 依赖于特定服务实现的组件将获取AutoFac工厂委托,该委托解析为特定于所需服务实现的工厂
  2. 反过来,服务工厂依赖于AutoFac工厂委托,该委托知道如何从服务的(运行时)构造函数参数创建特定的服务实现.
  3. 此方法使用本机AutoFac构造,并且在容器布线之外对AutoFac没有任何依赖性.

这是一个粗略准备的例子.请注意,多个工厂可以简化为一个通用工厂 - 但为了清楚起见,我已将其保留原样:

服务实施

public enum ServiceType
{
    NotSet,
    ServiceA,
    ServiceB
}

public interface IService
{
    string DoWork();
}

public class ServiceA : IService
{
    private readonly string _name;

    public ServiceA(string name)
    {          
        _name = name;
    }

    public string DoWork()
    {
        throw new NotImplementedException();
    }
}

public class ServiceB : IService
{
    private readonly string _name;

    public ServiceB(string name)
    {           
        _name = name;
    }

    public string DoWork()
    {
        throw new NotImplementedException();
    }
}
Run Code Online (Sandbox Code Playgroud)

服务工厂

public interface IServiceFactory
{
    IService Create(string name);
}

public class ServiceAFactory : IServiceFactory
{
    private readonly Func<string, ServiceA> _factory;

    public ServiceAFactory(Func<string, ServiceA> factory)
    {            
        _factory = factory;
    }

    public IService Create(string name)
    {
        return _factory(name);
    }
}

public class ServiceBFactory : IServiceFactory
{
    private readonly Func<string, ServiceB> _factory;

    public ServiceBFactory(Func<string, ServiceB> factory)
    {            
        _factory = factory;
    }

    public IService Create(string name)
    {
        return _factory(name);
    }
}
Run Code Online (Sandbox Code Playgroud)

服务注册

builder.RegisterType<ServiceA>().As<ServiceA>();
builder.RegisterType<ServiceB>().As<ServiceB>();
builder.RegisterType<ServiceAFactory>().Keyed<IServiceFactory>(ServiceType.ServiceA);
builder.RegisterType<ServiceBFactory>().Keyed<IServiceFactory>(ServiceType.ServiceB);
builder.RegisterType<ComponentWithServiceDependency>().As<ComponentWithServiceDependency>(); 
Run Code Online (Sandbox Code Playgroud)

用法示例

public class ComponentWithServiceDependency
{
    private readonly IService _service;

    public ComponentWithServiceDependency(IIndex<ServiceType, IServiceFactory> serviceFactories)
    {            
        // Resolve the ServiceB service implementation,
        // using the string "test" as its constructor dependency
        _service = serviceFactories[ServiceType.ServiceB].Create("test");
    }

    public string Test()
    {
        return _service.DoWork();
    }
}
Run Code Online (Sandbox Code Playgroud)