Ros*_*sky 4 .net c# multithreading dependency-injection simple-injector
我有以下代码:
public class TempForm : Form
{
private readonly IGoogleAuth _googleAuth;
private readonly IComAssistant _comAssistant;
public TempForm(IGoogleAuth googleAuth, IComAssistant comAssistant)
{
_googleAuth = googleAuth;
_comAssistant = comAssistant;
InitializeComponent();
}
private void ButtonClick(object sender, EventArgs e)
{
var excelThread = new Thread(() =>
{
//NEED NEW INSTANCE OF EXCEL_APP PER THREAD
using (IExcelApp excel = new ExcelApp(_comAssistant))
{
//Do stuff with excel.
excel.CreateWorkBook();
//...
}
});
excelThread.SetApartmentState(ApartmentState.STA);
excelThread.Start();
}
private void InitializeComponent()
{
//Initialize form components
}
}
Run Code Online (Sandbox Code Playgroud)
我没有问题IGoogleAuth
或IComAssistant
服务,因为它们Singletone
在容器中注册,我在表单构造函数中注入它们.
但是在ButtonClick
方法中我需要ExcelApp
每个新线程的新实例.
我能这样做:
using (ThreadScopedLifestyle.BeginScope(container)) {
var excel = container.GetInstance<IExcelApp>();
}
Run Code Online (Sandbox Code Playgroud)
但是这样我需要将container
声明的内容传递Program.cs
给我的TempForm
表单.
是否有可能在不通过容器本身的情况下实现这种行为?
如果不是 - container
在几个地方使用实例的最佳做法是什么.我们需要将它作为单例,或者将它们放在自己的ServiceLocator
实现中?
谢谢.
是否有可能在不通过容器本身的情况下实现这种行为?
是的,这当然是可能的.诀窍是将这个逻辑从Form组件中提取到它自己的组件中.换句话说,您创建聚合服务.例如:
public class TempForm : Form
{
private readonly IGoogleAuth _googleAuth;
private readonly IExcelExporter _exporter;
public TempForm(IGoogleAuth googleAuth, IExcelExporter exporter)
{
_googleAuth = googleAuth;
_exporter = exporter;
InitializeComponent();
}
private void ButtonClick(object sender, EventArgs e)
{
_exporter.Export(...);
}
private void InitializeComponent()
{
//Initialize form components
}
}
Run Code Online (Sandbox Code Playgroud)
在这里,我们将与生成excel文档相关的所有代码从Form中提取到其自己的组件中.
这种实现可能如下所示:
public class ExcelExporter : IExcelExporter
{
private readonly IComAssistant _comAssistant;
public ExcelExporter(IComAssistant comAssistant)
{
_comAssistant = comAssistant;
}
private void Export(...)
{
//NEED NEW INSTANCE OF EXCEL_APP PER THREAD
using (IExcelApp excel = new ExcelApp(_comAssistant))
{
//Do stuff with excel.
excel.CreateWorkBook();
//...
}
}
}
Run Code Online (Sandbox Code Playgroud)
注意这个组件本身没有线程概念.线程是该组件不应负责的问题.将此课程排除在本课程之外,使课程更容易理解,更容易测试.
但这确实意味着我们必须在某处实现这种线程逻辑.但是,我们希望将其从表格中删除ExcelExporter
.在这样做时,我们需要参考Container
.
需要访问的每段代码Container
都应集中在应用程序的启动代码中,即组合根.
将此线程行为添加到我们的新ExcelExporter
组件的有效方法是使用代理IExcelExporter
:
public class BackgroundExcelExporterProxy : IExcelExporter
{
private readonly Container _container;
private readonly Func<IExcelExporter> _excelExporterFactory;
public ExcelExporter(
Container container, Func<IExcelExporter> excelExporterFactory)
{
_container = container;;
_excelExporterFactory = excelExporterFactory;
}
private void Export(...)
{
var excelThread = new Thread(() =>
{
using (ThreadScopedLifestyle.BeginScope(container))
{
var exporter = _excelExporterFactory();
exporter.Export(...);
}
});
excelThread.SetApartmentState(ApartmentState.STA);
excelThread.Start();
}
}
Run Code Online (Sandbox Code Playgroud)
这个类依赖于Container
.当Export
调用它时,它将启动一个新的,Thread
并在该线程内它将启动一个新的线程范围.在该线程范围内,它将解析IExporter
具有其依赖项的新内容.
当使用该RegisterDecorator
方法在Simple Injector中注册此类时(就Simple Injector而言,这是一个装饰器),Simple Injector将原生地理解Func<IExcelExporter>
依赖关系,并将理解该委托应解析装饰实例的实例(ExcelExporter
在您的案件).
我们可以注册如下:
container.Register<IExcelExporter, ExcelExporter>();
container.RegisterDecorator<IExcelExporter, BackgroundExcelExporterProxy>(
Lifestyle.Singleton);
Run Code Online (Sandbox Code Playgroud)
这将产生以下对象图:
new TempForm(
MyGoogleAuth(...),
new BackgroundExcelExporterProxy(
container,
() => new ExcelExporter(new MyComAssistant(...))));
Run Code Online (Sandbox Code Playgroud)
我们需要将它设为单例,还是将它们放在自己的ServiceLocator实现中?
你可能会认为,BackgroundExcelExporterProxy
有一个服务定位器,但只要这个类所在内的成分根,它不是一个服务定位,为解释在这里.
归档时间: |
|
查看次数: |
554 次 |
最近记录: |