2017-09-16 8 views
0

からインスタンスを注入された:私は持って行動がFoo.DoSomethingが呼び出されるということですシンプルインジェクタ - アクセスは、私は次のような何かを持っている私が働いているアプリ内SimpleInjectorを使用していますバックグラウンドスレッド

public class Foo : IFoo 
{ 
    private readonly Bar _bar; 

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

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

バックグラウンドスレッド(Task.Run)とBarは、シングルトンのライフスタイルを持つアプリ(Windowsフォームアプリ)のMainメソッドに登録されています。私が気になるのは、Fooに提供されたBarの実装がスレッドセーフではない場合です。

私の主な問題は、Fooによって必要とされる状態がBarであり、この状態がメインスレッドによって先に設定されてから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; } 
} 

次は私がfooを使用して、フォームのアプリです:

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

バーとメインに関連するコードを表示してください。 – Steven

+0

@Steven私は質問を編集してより多くの情報を追加しました。それが役に立てば幸い。ありがとうございました –

答えて

0

シングルトンのライフスタイルを持つアプリのメインメソッド(Windowsフォームアプリ)。 Fooに提供されたBarの実装がスレッドセーフではない場合、私は懸念しています。

がケースでアプリケーションがBarにアクセス並列に演算を実行し、あなたがより良いBar -and値を確認して、スレッドセーフですreturns-こと。

Barとその値がの場合は変更不可能であり、アプリケーションの起動時に1回だけ設定されていれば問題ありません。 Barまたはその値が変更可能な場合は、状況が急速に難しくなり始める可能性がありますが、これはアプリケーションのニーズによって異なります。

のようなあなたは、共通のpitfalsを防ぐために従うべきfew general rules、あります

  • シングルトンは、スレッドセーフでなければなりません。
  • アプリケーションコードからのバックグラウンド・スレッドを開始しないでください:組成のルートにこれを移動します。

我々はについて語った最初のポイント。第2のポイントは、ボタンクリック内からTask.Runに電話するので、あなたのケースでも間違っていることです。一般に、アプリケーションコードは、操作が並列で実行されるかどうかについて心配すべきではありません。それらは、それが何であるかに応じて、特定の抽象化(この場合はIFoo)のみを使用する必要があります。これはAppのみTask.Runでラップせず、_foo.DoSomething();を呼び出す必要があることを意味します。

バックグラウンドスレッドで操作を実行することが重要な場合は、のプロキシまたはデコレータを作成して、の実数Fooへの呼び出しをラップします。このプロキシは、同様IFooを実装する場合、それはAppはこれについて知らなくても、スタンドインFoo用として使用することができます。

このモデルの例は、AsyncMailSenderProxyhere見出すことができます。

+0

答えのためのおかげで@スティーブン。たとえば、バーの状態が満たされ、初期化されるまで(アプリをミドルウェイするまで)、バーをFooに注入するのを遅らせたい場合は、どうすればこのことができますか?私がcontainer.GetInstanceを呼び出すとBarがFooに注入されるため、デコレータのメカニズムが動作していないようです。();それは早過ぎる。ありがとう。 –

関連する問題