如何制作ActivatorUtilities.CreateInstance方法使用不同的构造函数? &



是否有办法告诉ActivatorUtilities.CreateInstance<T>(IServiceProvider serviceProvider);方法尝试使用其他构造函数如果第一个无法构建?

我有一个有多个构造函数的类:

  • public ViewModelB(SomeDependency someDependency):这个只需要在DI容器中注册的SomeDependency
  • public ViewModelB(SomeDependency someDependency, GetUserRequest request):这个需要在DI容器中注册的SomeDependency和必须手动传递的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; }
}

谢谢。

我也遇到过同样的问题。最后我想出了这个解决方案:

我会使用类似工厂的东西,它可以通过调用方法来构造ServiceB

例如:

var serviceBFactory = ActivatorUtilities.CreateInstance<ServiceBFactory>(serviceProvider);
var instanceBWithoutParams = serviceBFactory.CreateServiceB();
var instanceBWithParams = serviceBFactory.CreateServiceB(new Request());

这样可以保持DI清洁。但这意味着ServiceBFactory需要知道哪些服务需要注入到ServiceB中。(这将是一个紧密耦合)它们作为一个包来。

我选择重新设计视图模型,而不是尝试在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);

假设你有一个这样的类:

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}");
}
}
}

最新更新