如果第一個建構式無法構造,有沒有辦法告訴ActivatorUtilities.CreateInstance<T>(IServiceProvider serviceProvider);方法嘗試使用其他建構式?
我有一個具有多個建構式的類:
public ViewModelB(SomeDependency someDependency): 這個只需要SomeDependency在 DI 容器中注冊public ViewModelB(SomeDependency someDependency, GetUserRequest request):這個需要SomeDependency在 DI 容器中注冊,GetUserRequest需要手動傳入
我正在嘗試激活它們并解決依賴關系,如下所示:
IServiceProvider serviceProvider; //this gets passed from somewhere
Guid userId; //this gets passed manually by the caller
//works
var instanceAWithoutParams = ActivatorUtilities.CreateInstance<ViewModelA>(serviceProvider);
//works
var instanceAWithParams = ActivatorUtilities.CreateInstance<ViewModelA>(serviceProvider, new[] { new GetUserRequest { UserId = userId } });
//does NOT work, it tries to use the first constructor and fails
var instanceBWithoutParams = ActivatorUtilities.CreateInstance<ViewModelB>(serviceProvider);
//works
var instanceBWithParams = ActivatorUtilities.CreateInstance<ViewModelB>(serviceProvider,, new[] { new GetUserRequest { UserId = userId } });
instanceBWithoutParams由于無法決議request引數,激活失敗。它嘗試使用第一個建構式,并且在激活失敗時不檢查其他建構式。
這是服務的樣子,它們相同,但有一個區別:建構式的順序。
public class ViewModelA
{
private readonly SomeDependency _someDependency;
private readonly GetUserRequest? _request;
public ViewModelA(SomeDependency someDependency)
{
_someDependency = someDependency;
}
public ViewModelA(SomeDependency someDependency, GetUserRequest request)
{
_someDependency = someDependency;
_request = request;
}
}
public class ViewModelB
{
private readonly SomeDependency _someDependency;
private readonly GetUserRequest? _request;
public ViewModelB(SomeDependency someDependency, GetUserRequest request)
{
_someDependency = someDependency;
_request = request;
}
public ViewModelB(SomeDependency someDependency)
{
_someDependency = someDependency;
}
}
public class GetUserRequest
{
public Guid UserId { get; set; }
}
謝謝。
uj5u.com熱心網友回復:
我在同樣的問題上苦苦掙扎。最終我想出了這個解決方案:
我會使用類似工廠的東西,它可以ServiceB通過呼叫方法來構建。
例如:
var serviceBFactory = ActivatorUtilities.CreateInstance<ServiceBFactory>(serviceProvider);
var instanceBWithoutParams = serviceBFactory.CreateServiceB();
var instanceBWithParams = serviceBFactory.CreateServiceB(new Request());
這樣你就可以讓你的 DI 保持干凈。但這意味著ServiceBFactory 需要知道哪些服務需要注入到ServiceB 中。(所以這將是一個緊密的耦合)它們作為一個包來。
uj5u.com熱心網友回復:
我選擇重新設計視圖模型,而不是嘗試在 DI 服務旁邊傳遞可選引數(感謝 Steven 提供的有用文章:1和2)。
似乎也沒有辦法讓該ActivatorUtilities.CreateInstance<T>(IServiceProvider serviceProvider);方法在一個失敗后嘗試其他建構式,所以這就是我編輯的解決方案的樣子。
我已經將可選引數的初始化移出建構式,這樣我就只有一個只接受可注射的建構式。然后通過該TakeParameter方法單獨傳遞引數。我能想到的唯一缺點是引數不能再存在readonly了,我可以忍受。
我的自定義激活器實用程式:
public interface IAcceptParameter<T>
{
void TakeParameter(T parameter);
}
public static class CustomActivator
{
public static T CreateInstance<T>()
{
return ActivatorUtilities.CreateInstance<T>(_serviceProvider);
}
public static T CreateInstanceWithParam<T, K>(K parameter) where T : IAcceptParameter<K>
{
var instance = ActivatorUtilities.CreateInstance<T>(_serviceProvider);
instance.TakeParameter(parameter);
return instance;
}
}
更改視圖模型
public class SomeViewModel : IAcceptParameter<Guid>
{
private readonly SomeDependency _someDependency;
private Guid? _userId;
public SomeViewModel(SomeDependency someDependency)
{
_someDependency = someDependency;
}
public void TakeParameter(Guid parameter){
_userId = parameter;
}
}
我如何使用它
var instanceWithoutParam = CustomActivator.CreateInstance<SomeViewModel>(serviceProvider);
Guid userId;
var instanceWithParam = CustomActivator.CreateInstanceWithParam<SomeViewModel, Guid>(serviceProvider, userId);
uj5u.com熱心網友回復:
假設您有這樣的課程:
public class a
{
public string p { get; set; }
public a()
{
p = "default constructor";
}
public a(string pv)
{
p = pv;
}
}
您可以使用.GetConstructor方法來使用特定的建構式:
public class Program
{
static void Main(string[] args)
{
var c = typeof(a).GetConstructor(new Type[] { typeof(string) });
if (c != null)
{
var myA = (a)c.Invoke(new object[] { "new value" });
Console.WriteLine($"Value of p is {myA.p}");
}
}
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/qianduan/481269.html
