Es ist zu beachten, dass die empfohlene Methode die Verwendung des Optionsmusters ist . Es gibt jedoch Anwendungsfälle, in denen dies unpraktisch ist (wenn Parameter nur zur Laufzeit bekannt sind, nicht zur Start- / Kompilierungszeit) oder Sie eine Abhängigkeit dynamisch ersetzen müssen.
Dies ist sehr nützlich, wenn Sie eine einzelne Abhängigkeit ersetzen müssen (sei es eine Zeichenfolge, eine Ganzzahl oder eine andere Art von Abhängigkeit) oder wenn Sie eine Bibliothek eines Drittanbieters verwenden, die nur Zeichenfolgen- / Ganzzahlparameter akzeptiert und Laufzeitparameter benötigen.
Sie können CreateInstance (IServiceProvider, Object []) als Verknüpfungshand versuchen (nicht sicher, ob es mit Zeichenfolgenparametern / Werttypen / Grundelementen (int, float, string) funktioniert, nicht getestet) (Sie haben es einfach ausprobiert und bestätigt, dass es funktioniert, auch mit mehrere Zeichenfolgenparameter), anstatt jede einzelne Abhängigkeit von Hand aufzulösen:
_serviceCollection.AddSingleton<IService>(x =>
ActivatorUtilities.CreateInstance<Service>(x, "");
);
Die Parameter (letzter Parameter von CreateInstance<T>
/ CreateInstance
) definieren die Parameter, die ersetzt werden sollen (nicht vom Anbieter aufgelöst). Sie werden von links nach rechts angewendet, sobald sie angezeigt werden (dh die erste Zeichenfolge wird durch den ersten Parameter vom Typ "Zeichenfolge" des zu instanziierenden Typs ersetzt).
ActivatorUtilities.CreateInstance<Service>
wird an vielen Stellen verwendet, um einen Dienst aufzulösen und eine der Standardregistrierungen für diese einzelne Aktivierung zu ersetzen.
Wenn Sie zum Beispiel haben eine Klasse mit dem Namen MyService
, und es hat IOtherService
, ILogger<MyService>
als Abhängigkeiten und Sie wollen den Dienst lösen , aber den Standard - Service ersetzen IOtherService
(sagen sein OtherServiceA
) mit OtherServiceB
, man könnte etwas tun , wie:
myService = ActivatorUtilities.CreateInstance<Service>(serviceProvider, new OtherServiceB())
Dann wird der erste Parameter IOtherService
wird erhalten OtherServiceB
injiziert, anstattOtherServiceA
aber die übrigen Parameter aus dem Behälter kommen.
Dies ist hilfreich, wenn Sie viele Abhängigkeiten haben und nur eine einzelne speziell behandeln möchten (dh einen datenbankspezifischen Anbieter durch einen Wert ersetzen möchten, der während der Anforderung oder für einen bestimmten Benutzer konfiguriert wurde, was Sie nur zur Laufzeit und während einer Anforderung und wissen nicht wenn die Anwendung erstellt / gestartet wird).
Sie können stattdessen auch die ActivatorUtilities.CreateFactory-Methode (Type, Type []) verwenden , um die Factory-Methode zu erstellen, da sie eine bessere Leistung bietet. GitHub Reference and Benchmark .
Später ist eine nützlich, wenn der Typ sehr häufig aufgelöst wird (z. B. in SignalR und anderen Szenarien mit hohen Anforderungen). Grundsätzlich würden Sie ein ObjectFactory
Via erstellen
var myServiceFactory = ActivatorUtilities.CreateFactory(typeof(MyService), new[] { typeof(IOtherService) });
Speichern Sie es dann (als Variable usw.) und rufen Sie es bei Bedarf auf
MyService myService = myServiceFactory(serviceProvider, myServiceOrParameterTypeToReplace);
## Update: Ich habe es selbst versucht, um zu bestätigen, dass es auch mit Zeichenfolgen und Ganzzahlen funktioniert, und es funktioniert tatsächlich. Hier das konkrete Beispiel, mit dem ich getestet habe:
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);
}
Druckt
Output: Hello Tseng Stackoverflow