我想用不同的构造函数参数注册两个相同类型的服务(不使用接口).

例如,到目前为止,我有:

builder.Services.AddScoped(x => new WeatherForecastService("param1", "param2"));
builder.Services.AddScoped(x => new WeatherForecastService("param3", "param4"));

我已经看到我可以创建一个"命名"类型,但它在发送构造函数参数时似乎不起作用.

理想情况下,这样的东西会很好:

builder.Services.AddScoped(x => new WeatherForecastService("param1", "param2")).Name("my_first_service_named");

builder.Services.AddScoped(x => new WeatherForecastService("param3", "param4")).Name("my_second_service_named");

推荐答案

我假设您正在使用.NET依赖项注入库(Microsoft.Extensions.DependencyInjection)? 然而,这一原则适用于国际奥委会图书馆.只有登记会有所不同.

You can create a new concrete type, of course.
But since you only have different configurations of the same type, depending on the exact context you could introduce an abstract factory or a factory delegate.
The factory allows to create the same instance with different configurations. The advantage of factories is that they allow to create different configurations dynamically (where the required configuration is not know in advance).

根据实际的IOC库,您可能有其他特定于库的选项.例如,有些支持将命名服务与属性一起使用.

解决方案1:工厂代表

大多数IOC库都支持工厂委托来实现简单工厂.您只需将Func定义为构造函数参数,并注册产品类型.MOST将自动为您创建代表..NET IOC要求您显式注册Func:

注册工厂代表:

builder.Services.AddSingleton<Func<string, string, WeatherForecastService>>(
  serviceProvider => 
    (parameter1, parameter2) => new WeatherForecastService(parameter1, parameter2);

将工厂声明为依赖项并使用它:

class SomeType
{
  private WeatherForecastService WeatherForecastService { get; }
  public SomeType(Func<string, string, WeatherForecastService>, serviceFactory)
  {
    this.WeatherForecastService = serviceFactory.Invoke("param1", "param2");
  }
}

class SomeOtherType
{
  private WeatherForecastService WeatherForecastService { get; }
  public SomeType(Func<string, string, WeatherForecastService>, serviceFactory)
  {
    this.WeatherForecastService = serviceFactory.Invoke("param3", "param4");
  }
}

解决方案2:抽象工厂

如果配置不是动态的,您可以创建一个工厂来返回预先配置的实例(当然,动态配置也可以由调用者显式决定如何配置实例):

定义工厂:

class WeatherForecastServiceFactory : IWeatherForecastService
{
  public WeatherForecastService CreateEuropeService() 
    => new WeatherForecastService("param1", "param2"); 

  public WeatherForecastService CreateAfricaService() 
    => new WeatherForecastService("param3", "param4");
} 

注册工厂:

builder.Services.AddSingleton<IWeatherForecastServiceFactory, WeatherForecastServiceFactory>();

声明依赖项:

class SomeType
{
  private WeatherForecastService ForecastEurope { get; }
  public SomeType(IWeatherForecastServiceFactory serviceFactory)
  {
    this.ForecastEurope = serviceFactory.CreateEuropeService();
  }
}

解决方案3:封装配置(推荐、最方便、最可靠)

在静态配置变化的情况下,使用抽象工厂的替代方案(解决方案2)是 for each 配置定义一个专用类.此解决方案为您提供了非常受欢迎的编译器支持,以确保使用正确的配置:这消除了出现严重错误的可能性:

class WeatherForecastEurope : WeatherForecastService
{
  public WeatherForecastEurope() : base("param1", "param2")
  {}
}

class WeatherForecastAfrica : WeatherForecastService
{
  public WeatherForecastEurope() : base("param3", "param4")
  {}
}

Csharp相关问答推荐

ListaryImportProperty的默认DllImportSearchPathsProperty行为

Serilog SQL服务器接收器使用UTC作为时间戳

以自动方式注销Azure身份应用程序

EF Core在请求列表时忽略列,但在按ID获取时包含

不仅仅是一个简单的自定义按钮

使用Audit.EntityFramework,我如何将外键的值设置为相关实体上的属性?

C#EF Core 8.0表现与预期不符

为什么SignalR在每个Blazor服务器应用程序启动时最多启动8个服务器?

方法从数据表中只 Select 一个条件?

StackExchange.Redis.RedisServerException:调用ITransaction.ExecuteAsync()时出现错误未知命令取消监视

C# CompareTo()和Compare()可以返回除-1和1以外的整数吗?

Blazor Web App WASM的两个独立项目令人困惑

升级后发出SWITCH语句

Content WithTargetPath实际上是有效的MSBuild项吗?

如何从非异步任务中正确返回TypeResult

在.NET8中如何反序列化为私有字段?

错误:此版本的Visual Studio无法打开以下项目

身份验证中间件如何处理多个方案

如何获取我在SQL中输入的值

如何通过WinSCP判断SFTP会话中使用的加密算法?