2017-09-16 55 views
0

我的应用程序中使用SimpleInjector我的工作,在那里我有类似以下的东西:简单的注射器 - 访问来自后台线程注入的情况下

public class Foo : IFoo 
{ 
    private readonly Bar _bar; 

    public Foo(Bar bar)    
    { 
     _bar = bar; 
    } 

    public void DoSomething() 
    {       
     IEnumberable<Order> orders = _bar.Orders;    
    } 
} 

我的行为是Foo.DoSomething被称为从后台线程(Task.Run)和Bar注册在应用程序的主要方法(Windows窗体应用程序)与单身生活方式。我所关心的是如果Bar提供给Foo的实现不是线程安全的。

我的主要问题是Bar的状态是Foo所需要的,这个状态是在调用Foo.DoSomething之前由主线程设置的。我已经四处寻找解决方案,我面临的这种情况,但我无法找到一个帮助(除非我只是走错了方向)。

我看过this页面上的建议,在后台线程上执行实例时使用装饰器。然而,这并没有帮助,因为Bar的状态设置在不同的线程(主线程)上,并且使用装饰器将只创建一个没有状态的新实例Bar

所以我想我的问题是我只需要注册酒吧作为一个单身人士,并确保注册的实现是线程安全的,或者是有明显的解决方案,这个问题,正在盯着我在脸上但我似乎无法看到?

希望我提供的信息是足够的。如果您需要更多信息,请告诉我。

感谢

更新 Bar只是包含信息的列表类在整个应用程序的需要。例如:

public class Bar: IBar 
{ 
    // Not using orders or products, but just for purpose of the example 
    // These are initialized early on in the App process because early 
    // steps of the app (which are on the main thread) need them. 
    public IEnumerable<Order> Orders { get; private set; } 

    public IEnumerable<Product> Products { get; private set; } 
} 

以下是我使用美孚形式应用:

public partial class App: Form 
{   
    private readonly IFoo _foo; 
    public App(IFoo foo) 
    { 
     InitializeComponent(); 
     _foo = foo;    
    } 

    public btn1_Click() 
    { 
     // This is just for the purpose of showing that the data inside Bar 
     // is loaded on the main thread before Foo.DoSomething is run. In 
     // the real app the Bar data is loaded at previous steps of the app 
     // (the app is a wizard like app). 
     LoadBarData(); 
     Task.Run(() => 
     { 
      _foo.DoSomething(); 
     }); 

     // The issue would be if for example Bar is changed here while the 
     // background thread is running. In my app it doesn't really change 
     // here, but I want to make sure no issues arise in all scenarios, 
     // whether it changes or not.    
    } 
} 

最后这里是我的主要方法:

[STAThread] 
static void Main() 
{ 
    Application.EnableVisualStyles(); 
    Application.SetCompatibleTextRenderingDefault(false); 
    using (Container container = new Container()) 
    { 
     container.Register<IBar, Bar>(Lifestyle.Singleton); 
     container.Register<IFoo, Foo>(Lifestyle.Singleton); 
     container.Register<App>(); 
    } 
    Application.Run(container.GetInstance<App>()); 
} 
+0

请显示Bar和Main的相关代码。 – Steven

+0

@Steven我编辑了这个问题以包含更多信息。希望能帮助到你。谢谢 –

回答

0

酒吧在注册单身生活方式的应用程序(Windows窗体应用程序)的主要方法。我所关心的是如果为Foo提供的Bar的实现不是线程安全的。

如果您的应用程序运行在并行访问Bar操作,你最好确保Bar - 和值它returns-是线程安全的。

这应该不是一个问题,如果Bar和它的值是不可变的并在应用程序启动过程中设置一次。如果Bar或其值是可变的,事情可能会开始变得更加困难,但这一切都取决于您的应用程序的需求。

有一个few general rules,你应该遵循预防常见pitfals,如:

  • 单身应该是线程安全的。
  • 请勿从应用程序代码中启动后台线程:将其移至组合根目录。

我们谈到的第一点。第二点是你的情况也出错了,因为你在你的按钮点击中调用了Task.Run。一般来说,应用程序代码不应该担心操作是否并行运行。他们应该只使用给定的抽象(在这种情况下为IFoo)。这意味着App应该只调用_foo.DoSomething();,而不包含在Task.Run中。

在运行的情况下在后台线程上运行是非常重要的,代理或装饰的IFoo可以创建一个包装在Task.Run调用真正的Foo。当该代理也执行IFoo时,它可以用作Foo的备用,而不需要App必须知道这一点。

这个模型的一个例子可以找到hereAsyncMailSenderProxy

+0

谢谢你的回答@Steven。例如,如果我想延迟将Bar注入到Foo中,直到Bar状态被填充并初始化(这是通过应用程序的中途),我将如何能够实现此目的?当我调用container时,装饰器机制似乎不起作用,因为Bar会被注入到Foo中。这太早了。谢谢。 –

相关问题