Perlu dicatat bahwa cara yang disarankan adalah dengan menggunakan Pola Opsi . Tetapi ada kasus penggunaan yang tidak praktis (ketika parameter hanya diketahui saat runtime, bukan pada waktu startup / kompilasi) atau Anda perlu mengganti dependensi secara dinamis.
Ini sangat berguna saat Anda perlu mengganti satu dependensi (baik itu string, integer, atau jenis dependensi lain) atau saat menggunakan library pihak ketiga yang hanya menerima parameter string / integer dan Anda memerlukan parameter waktu proses.
Anda dapat mencoba CreateInstance (IServiceProvider, Object []) sebagai jalan pintas (tidak yakin ini berfungsi dengan parameter string / tipe nilai / primitif (int, float, string), belum diuji) (Baru saja mencobanya dan mengonfirmasi kerjanya, bahkan dengan beberapa parameter string) daripada menyelesaikan setiap dependensi dengan tangan:
_serviceCollection.AddSingleton<IService>(x =>
ActivatorUtilities.CreateInstance<Service>(x, "");
);
Parameter (parameter terakhir dari CreateInstance<T>
/CreateInstance
) menentukan parameter yang harus diganti (tidak diselesaikan dari penyedia). Mereka diterapkan dari kiri ke kanan saat muncul (yaitu string pertama akan diganti dengan parameter tipe string pertama yang akan dipakai).
ActivatorUtilities.CreateInstance<Service>
digunakan di banyak tempat untuk menyelesaikan layanan dan menggantikan salah satu registrasi default untuk aktivasi tunggal ini.
Misalnya jika Anda memiliki kelas bernama MyService
, dan memiliki IOtherService
, ILogger<MyService>
sebagai dependensi dan Anda ingin menyelesaikan layanan tetapi mengganti layanan default IOtherService
(katakanlah OtherServiceA
) dengan OtherServiceB
, Anda dapat melakukan sesuatu seperti:
myService = ActivatorUtilities.CreateInstance<Service>(serviceProvider, new OtherServiceB())
Kemudian parameter pertama IOtherService
akan OtherServiceB
diinjeksikan, bukan OtherServiceA
parameter yang tersisa akan datang dari container.
Ini berguna ketika Anda memiliki banyak dependensi dan hanya ingin memperlakukan satu dependensi secara khusus (yaitu mengganti penyedia khusus database dengan nilai yang dikonfigurasi selama permintaan atau untuk pengguna tertentu, sesuatu yang hanya Anda ketahui pada waktu proses dan selama permintaan dan bukan saat aplikasi dibangun / dimulai).
Anda juga dapat menggunakan Metode ActivatorUtilities.CreateFactory (Type, Type []) untuk membuat metode pabrik, karena metode ini menawarkan Referensi dan Tolok Ukur GitHub dengan kinerja yang lebih baik .
Nanti berguna ketika tipe diselesaikan sangat sering (seperti di SignalR dan skenario permintaan tinggi lainnya). Pada dasarnya Anda akan membuat ObjectFactory
melalui
var myServiceFactory = ActivatorUtilities.CreateFactory(typeof(MyService), new[] { typeof(IOtherService) });
kemudian cache (sebagai variabel dll) dan panggil jika diperlukan
MyService myService = myServiceFactory(serviceProvider, myServiceOrParameterTypeToReplace);
## Pembaruan: Coba sendiri untuk mengonfirmasi bahwa ini juga berfungsi dengan string dan integer, dan memang berhasil. Berikut contoh konkret yang saya uji dengan:
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);
}
Cetakan
Output: Hello Tseng Stackoverflow