Следует отметить, что рекомендуемый способ - использовать шаблон параметров .Но есть случаи использования, когда это непрактично (когда параметры известны только во время выполнения, а не во время запуска / компиляции) или вам нужно динамически заменить зависимость.
Это очень полезно, когда вам нужно заменить одну зависимость(будь то строка, целое число или другой тип зависимости) или при использовании сторонней библиотеки, которая принимает только строковые / целочисленные параметры, и вам требуется параметр времени выполнения.
Вы можете попробовать 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 для создания фабричного метода, поскольку он предлагает лучшую производительность GitHub Reference и Тест .
Позже это полезно, когда тип разрешается очень часто (например, в 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 class HelloWorldService
{
public string Hello(string name) => $"Hello {name}";
public string Hello(string firstname, string lastname) => $"Hello {firstname} {lastname}";
}
// Just a helper method to shorten code registration code
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