应该注意的是,推荐的方法是使用选项模式。但是在某些情况下,它不切实际(仅在运行时才知道参数,而在启动/编译时才知道),或者您需要动态替换依赖项。
当您需要替换单个依赖项(字符串,整数或其他类型的依赖项)或使用仅接受字符串/整数参数且需要运行时参数的第三方库时,它非常有用。
您可以尝试使用CreateInstance(IServiceProvider,Object [])作为快捷方式(不确定它是否适用于字符串参数/值类型/基元(int,float,字符串),未经测试) (只需尝试一下并确认其工作原理,即使多个字符串参数),而不是手动解决每个依赖关系:
_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 [])方法创建工厂方法,因为它提供了更好的性能GitHub Reference和Benchmark。
当类型非常频繁地解析时(例如在SignalR和其他高请求场景中),后面的一个很有用。基本上,您将创建一个ObjectFactory
Via
var myServiceFactory = ActivatorUtilities.CreateFactory(typeof(MyService), new[] { typeof(IOtherService) });
然后将其缓存(作为变量等)并在需要时调用它
MyService myService = myServiceFactory(serviceProvider, myServiceOrParameterTypeToReplace);
## Update:我自己尝试过一次,以确认它也可以用于字符串和整数,并且确实可以工作。这是我测试过的具体示例:
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