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

时间:2014-07-28 19:41:58

标签: 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
    }
}

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

我一直在浏览AutoFac文档,试图找到一种类型安全的方法来解析这样的组件而无需直接引用容器。如果我只有IService的一个实现,那么我可以使用Delegate Factory将运行时参数传递给构造函数。但是,我有两个实现,并且还应该在运行时确定应该使用的实现。如果我没有name构造函数参数,那么我可以register the two components by Key and the resolve using IIndex

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

2 个答案:

答案 0 :(得分: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];
    }
}

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

  1. 依赖于特定服务实现的组件接受AutoFac工厂委托,该委托解析为特定于所需服务实现的工厂
  2. 反过来,服务工厂依赖于AutoFac工厂委托,该委托知道如何从服务的(运行时)构造函数参数创建特定服务实现
  3. 此方法使用本机AutoFac构造,并且在容器布线之外对AutoFac没有任何依赖性。
  4. 这是一个粗略准备的例子。请注意,多个工厂可以简化为一个通用工厂 - 但为了清晰起见,我已将其保留原样:

    服务实施

    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();
        }
    }
    

    服务工厂

    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);
        }
    }
    

    服务注册

    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>(); 
    

    使用示例

    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();
        }
    }
    

答案 1 :(得分:1)

您可以使用Interface Segregation。

public interface IService
{
    void DoWork();
}

public interface IServiceA : IService
{
}

public interface IServiceB : IService
{
}

public class ServiceA : IServiceA
{
    private readonly string _name;

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

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

public class ServiceB : IServiceB
{
    private readonly string _name;

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

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

然后,您可以像这样注入委托工厂:

public class ClientA
{
    public ClientA(Func<string, IServiceA> serviceAFactory, Func<string, IServiceB> serviceBFactory)
    {
        this.serviceAFactory = serviceAFactory;
        this.serviceBFactory = serviceBFactory;
    }

    public CreateServices()
    {
        var runTimeName = "runTimeName";
        var serviceA = this.serviceAFactory(runTimeName);
        var serviceB = this.ServiceBFactory(runTimeName);
    }
}

Autofac将为您注册的每个接口生成一个委托工厂:

public class MyModule : Module
{
    protected override void Load(ContainerBuilder builder)
    {
        builder.RegisterType<ServiceA>()
            .As<IService>()
            .As<IServiceA>();

        builder.RegisterType<ServiceB>()
            .As<IService>()
            .As<IServiceB>();
    }
}