Слід зазначити, що рекомендованим способом є використання шаблону параметрів . Але бувають випадки використання, коли це непрактично (коли параметри відомі лише під час виконання, а не під час запуску / компіляції) або вам потрібно динамічно замінити залежність.
Це дуже корисно, коли вам потрібно замінити одну залежність (будь то рядок, ціле число або інший тип залежності) або при використанні сторонньої бібліотеки, яка приймає лише параметри рядка / цілого числа, і вам потрібен параметр виконання.
Ви можете спробувати CreateInstance (IServiceProvider, Object []) як ярлик (не впевнений, що він працює з параметрами рядків / типами значень / примітивами (int, float, string), не перевірений) (Просто спробував і підтвердив свою роботу, навіть параметри рядка), а не розв'язувати кожну залежність вручну:
_serviceCollection.AddSingleton<IService>(x =>
ActivatorUtilities.CreateInstance<Service>(x, "");
);
Параметри (останній параметр CreateInstance<T>
/ CreateInstance
) визначають параметри, які слід замінити (не вирішено у постачальника). Вони застосовуються зліва направо, коли вони з'являються (тобто перший рядок буде замінений першим рядковим типом параметра типу, який потрібно створити).
ActivatorUtilities.CreateInstance<Service>
використовується в багатьох місцях для вирішення послуги та заміни однієї з реєстрацій за замовчуванням для цієї єдиної активації.
Наприклад , якщо у вас є клас з ім'ям MyService
, і вона має IOtherService
, ILogger<MyService>
як залежності , і ви хочете , щоб вирішити цю послугу , але замінити службу за умовчанням IOtherService
(кажуть , що його OtherServiceA
) з OtherServiceB
, ви могли б зробити що - щось на кшталт:
myService = ActivatorUtilities.CreateInstance<Service>(serviceProvider, new OtherServiceB())
Тоді IOtherService
буде OtherServiceB
введено перший параметр , а не OtherServiceA
інші параметри, але надходитимуть із контейнера.
Це корисно, коли у вас багато залежностей і ви хочете просто спеціально обробити одну (тобто замінити постачальника баз даних значенням, налаштованим під час запиту або для конкретного користувача, те, що ви знаєте лише під час виконання та під час запиту та не коли додаток будується / запускається).
Ви також можете використовувати метод ActivatorUtilities.CreateFactory (Тип, Тип []) для створення заводського методу, оскільки він пропонує кращу продуктивність GitHub Reference та Benchmark .
Пізніше такий корисний, коли тип вирішується дуже часто (наприклад, у SignalR та інших сценаріях високих запитів). В основному ви створили б ObjectFactory
прохідний
var myServiceFactory = ActivatorUtilities.CreateFactory(typeof(MyService), new[] { typeof(IOtherService) });
потім кешуйте його (як змінну тощо) і викликайте там, де це потрібно
MyService myService = myServiceFactory(serviceProvider, myServiceOrParameterTypeToReplace);
## Оновлення: Просто спробував сам, щоб підтвердити, що він також працює зі рядками та цілими числами, і він справді працює. Ось конкретний приклад, який я тестував:
class Program
{
static void Main(string[] args)
{
var services = new ServiceCollection();
services.AddTransient<HelloWorldService>();
services.AddTransient(p => p.ResolveWith<DemoService>("Tseng", "Stackoverflow"));
var provider = services.BuildServiceProvider();
var demoService = provider.GetRequiredService<DemoService>();
Console.WriteLine($"Output: {demoService.HelloWorld()}");
Console.ReadKey();
}
}
public class DemoService
{
private readonly HelloWorldService helloWorldService;
private readonly string firstname;
private readonly string lastname;
public DemoService(HelloWorldService helloWorldService, string firstname, string lastname)
{
this.helloWorldService = helloWorldService ?? throw new ArgumentNullException(nameof(helloWorldService));
this.firstname = firstname ?? throw new ArgumentNullException(nameof(firstname));
this.lastname = lastname ?? throw new ArgumentNullException(nameof(lastname));
}
public string HelloWorld()
{
return this.helloWorldService.Hello(firstName, lastName);
}
}
public class HelloWorldService
{
public string Hello(string name) => $"Hello {name}";
public string Hello(string firstname, string lastname) => $"Hello {firstname} {lastname}";
}
static class ServiceProviderExtensions
{
public static T ResolveWith<T>(this IServiceProvider provider, params object[] parameters) where T : class =>
ActivatorUtilities.CreateInstance<T>(provider, parameters);
}
Відбитки
Output: Hello Tseng Stackoverflow