我在使用泛型和DI在MVC Core项目中一起工作时遇到了麻烦。我有一个泛型类(这只是一个片段)。我需要初始化输入和输出,因为它们如何在代码的其他部分中使用,所以我使用Activator来提供初始值和new()约束。
public class Message<TIn, TOut> :
where TIn : class, IMessagePart, new()
where TOut : class, IMessagePart, new() {
public Message(){}
public Message(TIn inpart, TOut outpart) {
Input = inpart;
Output = outpart;
}
public TIn Input { get; set; } = (TIn)Activator.CreateInstance(typeof(TIn));
public TOut Output { get; set; } = (TOut)Activator.CreateInstance(typeof(TOut));
}
我有其他类使用它们,它们有一些静态实用程序类。我正在尝试使用DI替换这些静态类。
public class Project : IMessagePart{
int y = 1;
var x = StaticUtilityClass.StaticMethod(y);
}
就像这样使用
var projectMessage = new Message<Project, Project>();
我正在将静态实用程序类转换为实例类并注入它们。我正在使用内置的.Net核心容器。我将实用程序转换为实例类,并将它们注册为容器中的具体单例。对于大多数事情,我可以做正常的事情 -
public class SomeClass{
private readonly UtilityClass _utility;
public SomeClass(UtilityClass utility){
_utility = utility;
var x = _utility.Method(1);
}
在我进入仿制药之前,事情一切正常。我不能在projectMessage上进行构造函数注入,因为泛型需要新建它并且它有new()约束,所以我需要一个无参数构造函数。如果我只添加一个注入构造函数,我得到
'Project'必须是具有public parameterless的非抽象类型 构造函数,以便在泛型类型中将其用作参数“TIn” 或方法'消息'。
如果我添加两个构造函数,Activator只会调用没有参数的构造函数,因此不会调用DI。我尝试了几种不同的方式使用CreateInstance的重载,但没有运气欺骗它。
这里有什么建议吗?我不知道我是否应该保持静态,尝试某种服务定位器方法,或者如果有不同的方式来编写泛型。
答案 0 :(得分:0)
您收到错误原因的答案是new()
限制。这指定参数must have a public parameterless constructor。这正是你的错误所说的。删除该约束应该可以解决该错误。但是,如果要使用DI,还有其他问题。
除了IMessagePart
之外,没有一个类具有支持接口。为了有效地使用DI,您需要定义IMessage
,IProject
等。然后您的容器可以在运行时创建特定实例,而不是像现在这样使用Activators 。所以你的Message
声明如下:
public class Message<TIn, TOut> : IMessage,
where TIn : class, IMessagePart
where TOut : class, IMessagePart
{
public TIn input { get; set; }
public TOut output { get; set; }
public Message(TIn inpart, TOut outpart) {
this.input = inpart;
this.output = outpart;
}
}
您可以将DI容器设置为:
public Startup()
{
var container = new DiContainer(); // I know this is the wrong name; I'm not familiar with the built in container naming and functionality.
container.Register<IMessage>();
container.Register<IMessagePart>();
container.Register<IProject>();
// Register other stuff here
}
更改特定容器的语法。您还可以选择将实例注册为:
container.Register<Message>(() => Message(part1, part2));
这样你就可以专门注入一个在启动时新建的Message
,但在大多数情况下这并不是很理想。通常,您希望DI容器根据需要动态创建实例(因此是接口),而不是使用单个具体实例化。当然也有例外; SQL连接是一种常见的连接。