可以使用约定基于ctor arg名称注入命名实例吗?

时间:2012-09-18 09:30:18

标签: c# dependency-injection structuremap

使用StructureMap,可以按惯例根据名称注入实例,如下所示:

CTOR:

public HomeController(IQuery getItemByProductNumberQuery, IQuery getCustomerById)

StructureMap config:

x.For<IQuery>().Add<GetItemByProductNumberQuery>().Named("getItemByProductNumberQuery");
x.For<IQuery>().Add<GetCustomerById>().Named("getCustomerById");

我正在使用遗留代码,因此更改DI容器是一项艰巨的任务,但了解其他容器解决手头问题的方法也很有趣。

1 个答案:

答案 0 :(得分:2)

在我看来,你缺少代码库中的抽象。在正常情况下,服务(在您的情况下为IQuery)应该是明确的,在您的情况下情况并非如此。通过参数名称识别它们通常容易出错,并导致难以维护的DI配置。这并不总是必须这样(可以在this example中看到),但它可能就在你的情况下。

要解决此问题,请将IQuery界面设为通用:

public interface IQuery<TParameters, TResult>
{
    TResult Handle(TParameters parameters);
}

这允许您通过其封闭的通用表示来注册此接口的所有实现,并允许您的控件依赖于此封闭的通用表示:

public HomeController(
    IQuery<GetItemByProductNumberParameters, Item> getItemQuery, 
    IQuery<GetCustomerByIdParameters, Customer> getCustomerById)

如您所见,每个查询都定义了一个“XXXParameters”对象。这是一个DTO,包含运行查询所需的所有参数。您HomeController中的代码可能如下所示:

public View Item(int productNumber)
{
    var parameters = new GetItemByProductNumberParameters
    {
        ProductNumber = productNumber,
        // other parameters here
    };

    Item item = this.getItemQuery.Handle(parameters);

    return this.View(item);
}

使用StructureMap批量注册所有IQuery<TParameter, TResult>实现可能有点困难,但this SO question might help。如果没有,使用另一个DI容器可能会产生更好的结果。

您可以在本文中找到有关您希望以这种方式为查询建模的原因的更多信息:Meanwhile… on the query side of my architecture