Использование Keyed Services для использования нескольких экземпляров одного типа; как ввести ключ IOptions?C#

Место общения программистов C#
Ответить Пред. темаСлед. тема
Anonymous
 Использование Keyed Services для использования нескольких экземпляров одного типа; как ввести ключ IOptions?

Сообщение Anonymous »

С появлением сервисов с ключами в .NET 8 мы теперь можем запрашивать конкретные реализации интерфейса в конструкторе:

Код: Выделить всё

public class MotorController
{
private readonly IMotor _motor;
public MotorController([FromKeyedServices("AxisX")] IMotor motor)
{
_motor = motor;
}
}
Это отличное дополнение к языку. Одним из полезных приложений может быть внедрение разных экземпляров одного и того же типа в разные классы на основе служебного ключа.
Примечание: я понимаю, что, вероятно, нет веских причин для этого. в приложениях ASP.NET, составляющих подавляющее большинство проектов C#. Однако для более нишевых приложений, над которыми я работаю, это будет полезным способом реализации нескольких экземпляров реальных физических устройств.
Препятствием для использования этого является то, что в настоящее время не существует способа ключа и сопоставления экземпляров IOptions, которые внедряются в классы; см. этот пример (максимально упрощенный):

Код: Выделить всё

using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;

// Create a simple configuration (stand-in for JSON file, etc.)
var configBuilder = new ConfigurationBuilder();

configBuilder.AddInMemoryCollection(new Dictionary
{
{ "Motors:X:AxisNumber", "1"},
{ "Motors:Y:AxisNumber", "2"},
{ "Motors:Z:AxisNumber", "3"}
});
var config = configBuilder.Build();

// Create a service collection with keyed services for different instances of the same type
var serviceCollection = new ServiceCollection();
serviceCollection.AddKeyedSingleton("X");
serviceCollection.AddKeyedSingleton("Y");
serviceCollection.AddKeyedSingleton("Z");

// QUESTION: How do we map different config sections to different keyed services?
serviceCollection.Configure(config.GetSection("Motors:X"));

var serviceProvider = serviceCollection.BuildServiceProvider();

var motorX = serviceProvider.GetRequiredKeyedService("X");
var motorY = serviceProvider.GetRequiredKeyedService("Y");
var motorZ = serviceProvider.GetRequiredKeyedService("Z");

Console.WriteLine("Motor X Axis: " + motorX.AxisNumber);
Console.WriteLine("Motor Y Axis: " + motorY.AxisNumber);
Console.WriteLine("Motor Z Axis: " + motorZ.AxisNumber);

public class Motor
{
public Motor(IOptions options)
{
AxisNumber = options.Value.AxisNumber;
}

public int AxisNumber { get; }
}

public class MotorOptions
{
public int AxisNumber { get; set; }
}
Выполняя этот пример, вы получаете один и тот же номер оси для каждого экземпляра, поскольку все они используют один экземпляр IOptions:

Код: Выделить всё

Motor X Axis: 1
Motor Y Axis: 1
Motor Z Axis: 1
Это можно сделать, вручную создав и привязав каждый экземпляр класса параметров, а затем передав соответствующий экземпляр параметров конструктору для каждого экземпляра службы с ключом:

Код: Выделить всё

MotorOptions optionsX = new();
MotorOptions optionsY = new();
MotorOptions optionsZ = new();

config.Bind("Motors:X", optionsX);
config.Bind("Motors:Y", optionsY);
config.Bind("Motors:Z", optionsZ);

// Create a service collection with keyed services for different instances of the same type
serviceCollection.AddKeyedSingleton("X", new Motor(Options.Create(optionsX)));
serviceCollection.AddKeyedSingleton("Y", new Motor(Options.Create(optionsY)));
serviceCollection.AddKeyedSingleton("Z", new Motor(Options.Create(optionsZ)));
Однако этот подход довольно неуклюж, особенно в менее тривиальном примере, где многие другие типы внедряются в конструктор вместе с аргументом IOptions.
Есть идеи по поводу более изящного решения этой проблемы, или это слишком далеко за пределами предполагаемого использования служб с ключами?

Подробнее здесь: https://stackoverflow.com/questions/786 ... o-key-inje
Реклама
Ответить Пред. темаСлед. тема

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

  • Похожие темы
    Ответы
    Просмотры
    Последнее сообщение

Вернуться в «C#»