Cần lưu ý rằng cách được khuyến nghị là sử dụng Mẫu tùy chọn . Nhưng có những trường hợp sử dụng mà nó không thực tế (khi các tham số chỉ được biết trong thời gian chạy, không phải lúc khởi động / biên dịch) hoặc bạn cần thay thế động một phụ thuộc.
Nó rất hữu ích khi bạn cần thay thế một phụ thuộc duy nhất (có thể là một chuỗi, số nguyên hoặc một loại phụ thuộc khác) hoặc khi sử dụng thư viện bên thứ 3 chỉ chấp nhận các tham số chuỗi / số nguyên và bạn yêu cầu tham số thời gian chạy.
Bạn có thể thử CreateInstance (IServiceProvider, Object []) như một tay tắt (không chắc nó hoạt động với tham số chuỗi / kiểu giá trị / nguyên thủy (int, float, string), chưa được kiểm tra) (Chỉ cần dùng thử và xác nhận nó hoạt động, ngay cả với nhiều tham số chuỗi) thay vì giải quyết mọi phụ thuộc bằng tay:
_serviceCollection.AddSingleton<IService>(x =>
ActivatorUtilities.CreateInstance<Service>(x, "");
);
Các tham số (tham số cuối cùng của CreateInstance<T>
/ CreateInstance
) xác định các tham số sẽ được thay thế (không được giải quyết từ trình cung cấp). Chúng được áp dụng từ trái sang phải khi chúng xuất hiện (nghĩa là chuỗi đầu tiên sẽ được thay thế bằng tham số kiểu chuỗi đầu tiên của kiểu sẽ được khởi tạo).
ActivatorUtilities.CreateInstance<Service>
được sử dụng ở nhiều nơi để giải quyết một dịch vụ và thay thế một trong các đăng ký mặc định cho lần kích hoạt duy nhất này.
Ví dụ: nếu bạn có một lớp được đặt tên MyService
, và nó có IOtherService
, ILogger<MyService>
là phụ thuộc và bạn muốn giải quyết dịch vụ nhưng thay thế dịch vụ mặc định của IOtherService
(giả sử nó OtherServiceA
) bằng OtherServiceB
, bạn có thể làm điều gì đó như:
myService = ActivatorUtilities.CreateInstance<Service>(serviceProvider, new OtherServiceB())
Sau đó, tham số đầu tiên của IOtherService
sẽ được OtherServiceB
đưa vào, thay vì OtherServiceA
nhưng các tham số còn lại sẽ đến từ vùng chứa.
Điều này hữu ích khi bạn có nhiều phụ thuộc và chỉ muốn xử lý đặc biệt một phụ thuộc duy nhất (tức là thay thế một nhà cung cấp cơ sở dữ liệu cụ thể bằng một giá trị được định cấu hình trong khi yêu cầu hoặc cho một người dùng cụ thể, điều mà bạn chỉ biết vào thời gian chạy và trong khi yêu cầu và không phải khi ứng dụng được xây dựng / khởi động).
Thay vào đó, bạn cũng có thể sử dụng phương thức ActivatorUtilities.CreateFactory (Type, Type []) để tạo phương thức gốc vì nó mang lại hiệu suất tốt hơn Tham chiếu GitHub và Điểm chuẩn .
Sau này hữu ích khi loại được giải quyết rất thường xuyên (chẳng hạn như trong SignalR và các tình huống yêu cầu cao khác). Về cơ bản, bạn sẽ tạo ObjectFactory
qua
var myServiceFactory = ActivatorUtilities.CreateFactory(typeof(MyService), new[] { typeof(IOtherService) });
sau đó lưu vào bộ nhớ cache (dưới dạng một biến, v.v.) và gọi nó khi cần thiết
MyService myService = myServiceFactory(serviceProvider, myServiceOrParameterTypeToReplace);
## Cập nhật: Tôi vừa thử tự mình xác nhận rằng nó cũng hoạt động với chuỗi và số nguyên, và nó thực sự hoạt động. Đây là ví dụ cụ thể mà tôi đã thử nghiệm:
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);
}
Bản in
Output: Hello Tseng Stackoverflow