具有运行时构造函数参数的键控委托工厂? [英] Keyed delegate factories with runtime constructor parameters?

查看:82
本文介绍了具有运行时构造函数参数的键控委托工厂?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

Lets say I have the following service and components:

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是在运行时确定的.

Notice that each component takes a constructor parameter name. Lets also say that name is determined at runtime.

我一直在浏览AutoFac文档,以尝试找到一种类型安全的方法来解析此类组件,而不必直接引用该容器.如果我只有IService的一种实现,那么我可以使用 Delegate Factory 来传递运行时构造函数的参数.但是,我有两种实现,并且必须在运行时确定应该使用的一种.如果没有name构造函数参数,则可以注册Key的两个组成部分和使用IIndex的解决方案

I've been going through the AutoFac documentation to try to find a type-safe way to resolve components like this without having to reference the container directly. If I had only one implementation of IService then I could just use a Delegate Factory to pass the runtime parameter to the constructor. However, I have two implementations, and the one that should be used must also be determined at runtime. If I didn't have the name constructor parameter then I could register the two components by Key and the resolve using IIndex

我不知道该怎么做.我可以通过某种方式结合使用代表工厂"和IIndex组件分辨率吗?还是有另一种无需直接引用容器即可注册和解析这两个组件的方法?

I can't figure out how to do both. Is there way I can somehow combine the use of Delegate Factories and IIndex component resolution? Or is there another way to register and resolve both components without having to directly reference the container?

推荐答案

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

As you say, your two individual requirements are natively supported by AutoFac.

  • Runtime resolution of constructor parameters can be implemented using Parameterized Instantiation
  • Resolution of a particular service implementation can be implemented using Keyed Service Lookup

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

However, there doesn't appear to be direct support for using these two constructs together. I.e. the following does not work:

public enum ServiceType
{
    ServiceA,
    ServiceB
}

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

为此,我的解决方法一直是根据服务实现将服务的分辨率移至工厂.然后,它的工作方式如下:

My work around for this has always been to move the resolution of the service to a factory per service implementation. This then works as follows:

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

这里有一个大致示例.请注意,可以将多个工厂简化为单个通用工厂-但为了清楚起见,我将其保留为原样:

Heres a rough-and-ready example. Note the multiple factories could be reduced to a single generic factory - but I've left it as-is for clarity:

服务实施

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

这篇关于具有运行时构造函数参数的键控委托工厂?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆