2017-09-16 72 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中。這太早了。謝謝。 –

相關問題