Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/21.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 是否有可能使用螺纹范围的方法和简单的注入器_C#_.net_Multithreading_Dependency Injection_Simple Injector - Fatal编程技术网

C# 是否有可能使用螺纹范围的方法和简单的注入器

C# 是否有可能使用螺纹范围的方法和简单的注入器,c#,.net,multithreading,dependency-injection,simple-injector,C#,.net,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;

我有以下代码:

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
    }
}
我对
IGoogleAuth
icomasistant
服务没有问题,因为它们在容器中注册为
Singletone
,我将它们注入表单构造函数中

但是在
按钮单击
方法中,我需要每个新线程的
ExcelApp
的新实例

我可以这样做:

using (ThreadScopedLifestyle.BeginScope(container)) {
    var excel = container.GetInstance<IExcelApp>();
}
使用(ThreadScopedLifestyle.BeginScope(容器)){
var excel=container.GetInstance();
}
但这样我需要将
程序.cs
中声明的
容器
传递到我的
临时表单
表单中

是否有可能在不传递容器本身的情况下实现这种行为

如果否-在多个地方使用
容器
实例的最佳实践是什么。 我们需要将其设置为单例,或者将它们放在自己的
ServiceLocator
实现中

谢谢

是否有可能在不传递容器本身的情况下实现这种行为

是的,当然有可能。诀窍是将这个逻辑从表单组件中提取到它自己的组件中。换句话说,您创建了一个。例如:

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
    }
}
在这里,我们将所有与从表单中生成excel文档相关的代码提取到它自己的组件中

这种实现可能如下所示:

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();
            //...
        }
    }
}
container.Register<IExcelExporter, ExcelExporter>();
container.RegisterDecorator<IExcelExporter, BackgroundExcelExporterProxy>(
    Lifestyle.Singleton);
请注意,这个组件本身没有线程的概念。线程是一个该组件不应负责的问题。在这个类中省略这个选项可以使这个类更容易理解和测试

这意味着我们必须在某个地方实现这个线程逻辑。然而,我们希望将其保留在表单和
ExcelExporter
之外。执行此操作时,我们需要对
容器的引用

需要访问
容器的每一段代码都应该集中在应用程序的启动代码中,即

将此线程行为添加到新的
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();
    }
}
这将生成以下对象图:

new TempForm(
    MyGoogleAuth(...),
    new BackgroundExcelExporterProxy(
        container,
        () => new ExcelExporter(new MyComAssistant(...))));
我们需要使其成为单例,还是将它们放在自己的ServiceLocator实现中


您可能认为
BackgroundExcelExporterProxy
有一个服务定位器,但只要该类驻留在组合根中,它就不是服务定位器,正如前面所解释的那样。

听起来您不应该在这里使用ServiceLocator。您应该始终注入所有服务,然后允许IoC容器在构造函数中解析它们,而不是使用服务定位器获取实例。请记住,单例使用的线程作用域实例不会被释放和重新解析,因此它将像单例一样运行。如果你的混音镜像这样,你需要非常小心地使用它们。谢谢你的解释!这正是我需要的。