如何在Winforms C#中定义依赖注入?
接口类别:
public interface ICategory
{
void Save();
}
类类别存储库:
public class CategoryRepository : ICategory
{
private readonly ApplicationDbContext _context;
public CategoryRepository(ApplicationDbContext contex)
{
_context = contex;
}
public void Save()
{
_context.SaveChanges();
}
}
表格1:
public partial class Form1 : Form
{
private readonly ICategury _ic;
public Form1(ICategury ic)
{
InitializeComponent();
_ic=ic
}
private void button1_Click(object sender, EventArgs e)
{
Form2 frm= new Form2();
frm.show();
}
}
表格2:
public partial class Form2 : Form
{
private readonly ICategury _ic;
public Form2(ICategury ic)
{
InitializeComponent();
_ic=ic
}
}
有问题?
- Program.cs中依赖项注入的定义
Application.Run(new Form1());
- Form 2调用时依赖项注入的定义
Form2 frm= new Form2();
frm.show();
3条答案
按热度按时间zujrkrfu1#
如何在Windows窗体(WinForms)中使用依赖项注入(DI)
要在WinForms .NET 5或6中使用DI,您可以执行以下步骤:
1.创建WinForms .NET应用程序
1.安装Microsoft.Extensions.Hosting包(它提供了一系列有用的功能,如DI、日志记录、配置等)
1.添加新接口
IHelloService.cs
:1.为您的服务
HelloService.cs
添加新实现:1.修改
Program.cs
:现在您可以将
IHelloService
注入Form1
并使用它:如果要使用DI显示
Form2
,首先需要将其注册为services.AddTransient<Form2>();
,然后根据Form2的用法,可以使用以下选项之一:Form1
的整个生命周期中只需要Form2
的一个示例,那么可以将其作为依赖项注入到Form1
的构造函数中,然后存储该示例,并在需要时显示它。但请注意:当你打开
Form1
的时候,它只会被初始化一次,并且不会被再次初始化。你也不应该释放它,因为它是唯一传递给Form1
的示例。Form2
的多个示例,或者需要多次初始化它,那么您可能会得到一个如下所示的示例:t3irkdon2#
除了Reza的回答之外,还有另一种方法,我的回答是originally published on my blog,但是,由于Stack Overflow是我们大多数人的主要信息来源,所以Reza回答下面的评论中链接的博客文章很容易被忽略。
接下来,这个解决方案基于Local Factory模式。
我们将从表单工厂开始
从现在起,此工厂将成为创建窗体的主要客户端接口。客户端代码将不再只调用
不,这是禁止的。相反,客户应该打电话
(and类似地用于其它形式)。
注意,当工厂被实现时,它自己并不做任何事情!相反,它将创建委托给一个神秘的提供者,这个提供者必须被注入到工厂中。这背后的想法是,提供者将被注入一次,在Composition Root中,这是代码中的一个地方,靠近启动。并且在应用程序堆栈中处于很高的位置,因此所有的依赖项都可以在那里解决,所以表单工厂不需要知道最终将向其注入哪个提供程序。
这种方法有一个显著的优势--根据实际需求,可以注入不同的提供者,例如,您可以为实际应用程序注入基于DI的提供者(我们稍后将编写它),为单元测试注入存根提供者。
无论如何,让我们有一个具有依赖项的表单:
这个表单依赖于一个服务,而这个服务将由构造函数提供。如果Form 1需要创建另一个表单Form 2,它会按照我们已经讨论过的方法来做:
然而,当表单不仅需要依赖服务,而且只需要一些自由参数(字符串、整型等)时,事情就变得更加复杂了。
但现在你需要更像
我们真的应该好好研究一下。再看一遍,一个现实生活中的生物可能需要
我们该怎么办?
为了得到一个完整的示例,接下来让我们修改表单工厂
让我们看看表单是如何定义的
你能看出其中的规律吗?
现在最后是Composition Root。让我们从服务开始
请注意,虽然接口应该位于堆栈中的某个位置(以便每个人都能识别),但是可以在任何位置自由提供实现(表单不需要引用实现!)然后,按照起始代码,最终提供表单工厂并设置容器
首先注意如何使用Host.CreateDefaultBuilder创建容器,这是一项简单的任务,然后注意如何注册服务以及如何在其他服务中注册表单。
对于没有任何依赖项的表单来说,这很简单,它只是
然而,如果表单同时需要服务和自由参数,那么它就注册为......表单创建函数,即返回实际表单的任意自由参数的Func。
这很聪明,我们使用一个本身使用工厂函数的注册机制来注册表单工厂函数(是的,一个工厂使用另一个工厂,一个Factception。如果你在这里感到困惑,请随意休息一下)我们注册的函数,Func〈string,Form 2〉有一个参数,something(对应于表单构造函数的free参数),但它的其他依赖项由容器(这正是我们想要的)解决。
这就是为什么实际的表单工厂需要注意它所解析的内容。
另一个分两步解析,我们首先解析工厂函数,然后使用创建的方法参数将其提供给函数:
就是这样。无论何时创建表单,
用于“简单”表单(仅具有服务依赖项)或仅
用于既需要服务依赖性又需要其他自由参数的表单。
jckbn6z73#
我只是想在这里添加它作为IFormFactory的一个替代模式,这是我通常使用的方法。
这样做的好处是,您不需要为添加的每个窗体和每组参数不断更改IFormFactory接口。
在应用程序启动时加载所有窗体,并将参数传递给show方法或其他可以在窗体上定义的基方法。
表单工厂
表格一
表格二