Следует отметить, что рекомендуется использовать шаблон параметров . Но есть случаи, когда это непрактично (когда параметры известны только во время выполнения, а не во время запуска / компиляции) или вам нужно динамически заменить зависимость.
Это очень полезно, когда вам нужно заменить одну зависимость (будь то строка, целое число или другой тип зависимости) или при использовании сторонней библиотеки, которая принимает только строковые / целочисленные параметры, и вам требуется параметр времени выполнения.
Вы можете попробовать 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 (Type, Type []) Method для создания метода factory вместо этого, поскольку он обеспечивает лучшую производительность 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