Tavsiye edilen yolun Seçenekler Modelini kullanmak olduğuna dikkat edilmelidir . Ancak, pratik olmadığı (parametreler başlangıç / derleme zamanında değil, yalnızca çalışma zamanında bilindiğinde) veya bir bağımlılığı dinamik olarak değiştirmeniz gereken kullanım durumları vardır.
Tek bir bağımlılığı değiştirmeniz gerektiğinde (bir dize, tam sayı veya başka bir bağımlılık türü) veya yalnızca dize / tamsayı parametrelerini kabul eden bir 3. taraf kitaplığı kullanırken ve çalışma zamanı parametresine ihtiyaç duyduğunuzda çok kullanışlıdır.
CreateInstance'ı (IServiceProvider, Object []) bir kısayol eli olarak deneyebilirsiniz ( dizge parametreleri / değer türleri / ilkeller (int, float, string) ile çalıştığından emin değilim, test edilmemiştir) (Sadece denedim ve çalıştığını doğruladı, her bir bağımlılığı elle çözmek yerine birden çok dize parametresi) :
_serviceCollection.AddSingleton<IService>(x =>
ActivatorUtilities.CreateInstance<Service>(x, "");
);
Parametreler (son parametre CreateInstance<T>
/ ' CreateInstance
) değiştirilmelidir parametreleri (sağlayıcıdan çözülmediği) tanımlar. Göründükleri anda soldan sağa uygulanırlar (yani ilk dize, somutlaştırılacak türün ilk dize-tipli parametresi ile değiştirilecektir).
ActivatorUtilities.CreateInstance<Service>
birçok yerde bir hizmeti çözümlemek ve bu tek etkinleştirme için varsayılan kayıtlardan birini değiştirmek için kullanılır.
Örneğin bir sınıf adında varsa MyService
, ve sahip olduğu IOtherService
, ILogger<MyService>
bağımlılıklar olarak ve hizmetin çözümlenmesinde ancak varsayılan hizmetini değiştirmek istiyor IOtherService
(ITS söylemek OtherServiceA
ile birlikte) OtherServiceB
gibi bir şey yapabileceğini,:
myService = ActivatorUtilities.CreateInstance<Service>(serviceProvider, new OtherServiceB())
Daha sonra ilk parametresi yerine enjekte IOtherService
edilecek OtherServiceB
, OtherServiceA
ancak kalan parametreler kaptan gelecektir.
Bu, çok sayıda bağımlılığınız olduğunda ve yalnızca tek birini özel olarak ele almak istediğinizde yararlıdır (yani, veritabanına özgü bir sağlayıcıyı, istek sırasında veya belirli bir kullanıcı için yapılandırılan bir değerle değiştirmek, yalnızca çalışma zamanında ve bir istek sırasında bildiğiniz bir şey ve uygulama oluşturulduğunda / başlatıldığında değil).
Daha iyi performans GitHub Reference ve Benchmark sunduğundan, bunun yerine fabrika yöntemi oluşturmak için ActivatorUtilities.CreateFactory (Type, Type []) Yöntemini de kullanabilirsiniz .
Daha sonra, tür çok sık çözüldüğünde (SignalR ve diğer yüksek istek senaryolarında olduğu gibi) kullanışlıdır. Temel olarak bir oluşturmak istiyorum ObjectFactory
aracılığıyla
var myServiceFactory = ActivatorUtilities.CreateFactory(typeof(MyService), new[] { typeof(IOtherService) });
daha sonra önbelleğe alın (değişken olarak vb.) ve gerektiğinde çağırın
MyService myService = myServiceFactory(serviceProvider, myServiceOrParameterTypeToReplace);
## Güncelleme: Dizeler ve tamsayılarla da çalıştığını doğrulamak için kendim denedim ve gerçekten işe yarıyor. İşte test ettiğim somut örnek:
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);
}
Baskılar
Output: Hello Tseng Stackoverflow