Динамический выбор реализации при внедрении зависимостей .NETC#

Место общения программистов C#
Ответить
Anonymous
 Динамический выбор реализации при внедрении зависимостей .NET

Сообщение Anonymous »

У меня есть две разные реализации для одного интерфейса, которые мне нужно зарегистрировать во внедрении зависимостей, и мне нужно условно проверить, какую реализацию создавать в данный момент.
Я использовал шаблон фабрики и делегат фабрики, и я просто хочу знать, есть ли лучший способ добиться этого.
Я буду использовать простые объекты, чтобы упростить задачу
IExampleService
internal interface IExampleService
{
public ExampleMode Mode { get; }
void Show();
}

internal enum ExampleMode
{
ExampleA,
ExampleB
}

ExampleAService

public ExampleMode Mode => ExampleMode.ExampleA;
public ExampleAService()
{
Console.WriteLine("Creating Example A");
}

public void Dispose()
{
Console.WriteLine("Disposing Example A");
}

public void Show()
{
Console.WriteLine("Example A Show");
}

ExampleBService
public ExampleMode Mode => ExampleMode.ExampleB;
public ExampleBService()
{
Console.WriteLine("Creating Example B");
}
public void Dispose()
{
Console.WriteLine("Disposing Example B");
}

public void Show()
{
Console.WriteLine("Example B Show");
}

Каков подходящий способ добиться выбора условной реализации при внедрении зависимостей.
Я использовал две разные реализации шаблона фабрики, первая использует Ienumerable, поэтому службы создаются DI и соответствуют назначенному зарегистрированному сроку службы, но я хочу избежать накладных расходов на создание экземпляров всех реализаций только для выбора одной.
Чтобы решить эту проблему, я использовал другой вариант фабрики, где я вручную создаю экземпляр требуемой службы но теперь мне нужно убедиться, что я удаляю этот объект вручную и эти службы больше не соответствуют зарегистрированному сроку службы службы.
ExampleServiceFactory
internal class ExampleServiceFactory : IExampleServiceFactory
{
private readonly IEnumerable exampleServices;

public ExampleServiceFactory(IEnumerable exampleServices)
{
this.exampleServices = exampleServices;
}

public IExampleService GetExampleService(ExampleMode mode)
{

//Using DI to inject Ienumerable of services
return exampleServices.FirstOrDefault(x => x.Mode == mode);

//Manually instantiate Services
//return mode switch
//{
// ExampleMode.ExampleA => new ExampleAService(),
// ExampleMode.ExampleB => new ExampleBService(),
// _ => throw new NotSupportedException(),
//};
}
}

и внедрение IServiceProvider в фабрику имело для меня смысл, но, похоже, это антишаблон

Еще один вариант локатора сервисов, которого следует избегать, — это внедрение фабрики, которая разрешает зависимости во время выполнения. Обе эти практики сочетают в себе стратегии инверсии управления.

в настоящее время я использую фабричный делегат для условного создания экземпляра требуемой реализации и передачи ее в оболочку, которую я могу свободно внедрять на другие страницы, в контроллер и т. д.
Program.cs
builder.Services.AddKeyedSingleton("ExampleA");
builder.Services.AddKeyedTransient("ExampleB");
builder.Services.AddTransient();

builder.Services.AddTransient();
//var exampleMode = ConfigurationManager.AppSettings["Device"];

builder.Services.AddTransient((ctx) =>
{
var configProvider = ctx.GetRequiredService();
var exampleMode = configProvider.GetExampleMode();
var service = exampleMode switch
{
ExampleMode.ExampleA => ctx.GetRequiredKeyedService("ExampleA"),
ExampleMode.ExampleB => ctx.GetRequiredKeyedService("ExampleB"),
_ => throw new InvalidOperationException()
};
return new GenericExampleService(service);
});


Подробнее здесь: https://stackoverflow.com/questions/782 ... -injection
Ответить

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

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

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

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

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