Należy zauważyć, że zalecanym sposobem jest użycie wzorca opcji . Ale są przypadki użycia, w których jest to niepraktyczne (kiedy parametry są znane tylko w czasie wykonywania, a nie w czasie uruchamiania / kompilacji) lub trzeba dynamicznie zastąpić zależność.
Jest to bardzo przydatne, gdy musisz zamienić pojedynczą zależność (czy to ciąg, liczbę całkowitą lub inny typ zależności) lub gdy używasz biblioteki innej firmy, która akceptuje tylko parametry typu string / integer i potrzebujesz parametru wykonawczego.
Możesz spróbować CreateInstance (IServiceProvider, Object []) jako skrótu (nie jestem pewien, czy działa z parametrami ciągów / typami wartości / prymitywami (int, float, string), nietestowane) (Właśnie wypróbowałem i potwierdziłem, że działa, nawet z wiele parametrów łańcuchowych) zamiast rozwiązywać ręcznie każdą zależność:
_serviceCollection.AddSingleton<IService>(x =>
ActivatorUtilities.CreateInstance<Service>(x, "");
);
Parametry (ostatni parametr z CreateInstance<T>
/ CreateInstance
) definiują parametry, które powinny zostać zastąpione (nierozpoznane przez dostawcę). Są one stosowane od lewej do prawej, gdy się pojawiają (tj. Pierwszy łańcuch zostanie zastąpiony pierwszym parametrem typu łańcuchowego typu, który ma być utworzony).
ActivatorUtilities.CreateInstance<Service>
jest używany w wielu miejscach do rozwiązywania usługi i zastępowania jednej z domyślnych rejestracji dla tej pojedynczej aktywacji.
Na przykład, jeśli masz klasę o nazwie MyService
i ma IOtherService
, ILogger<MyService>
jak zależnościami i chcesz rozwiązać usługę ale zastąpić domyślną usługę IOtherService
(powiedzmy ITS OtherServiceA
) z OtherServiceB
, można zrobić coś takiego:
myService = ActivatorUtilities.CreateInstance<Service>(serviceProvider, new OtherServiceB())
Wtedy pierwszy parametr IOtherService
zostanie OtherServiceB
wstrzyknięty, a nie OtherServiceA
pozostałe parametry będą pochodzić z kontenera.
Jest to przydatne, gdy masz wiele zależności i chcesz tylko traktować tylko jeden z nich (tj. Zastąpić konkretnego dostawcę bazy danych wartością skonfigurowaną podczas żądania lub dla określonego użytkownika, coś, co znasz tylko w czasie wykonywania i podczas żądania i nie podczas budowania / uruchamiania aplikacji).
Możesz także użyć metody ActivatorUtilities.CreateFactory (Type, Type []), aby zamiast tego utworzyć metodę fabryczną, ponieważ oferuje ona lepszą wydajność GitHub Reference i Benchmark .
Później jeden jest przydatny, gdy typ jest bardzo często rozpoznawany (na przykład w SignalR i innych scenariuszach z wysokim żądaniem). Zasadniczo utworzyłbyś ObjectFactory
via
var myServiceFactory = ActivatorUtilities.CreateFactory(typeof(MyService), new[] { typeof(IOtherService) });
następnie buforuj ją (jako zmienną itp.) i wywołuj ją w razie potrzeby
MyService myService = myServiceFactory(serviceProvider, myServiceOrParameterTypeToReplace);
## Aktualizacja: po prostu wypróbowałem to sam, aby potwierdzić, że działa również z ciągami znaków i liczbami całkowitymi, i rzeczywiście działa. Oto konkretny przykład, który przetestowałem z:
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);
}
Wydruki
Output: Hello Tseng Stackoverflow