2012-02-15 15 views
2

私のサイトでは、シングルトンオブジェクトとしてインスタンス化されるクラスDataAdapterがあります。そのクラスは、この達成するためにコードを私は怠け者シングルトンになりたい人の性質を持っています。SingletonプロパティのNet Lazy初期化

private readonly object _personLock = new object(); 
private volatile IPersonManager _person; 
public IPersonManager Person 
{ 
    get 
    { 
     if (_person == null) 
     { 
      lock (_personLock) 
      { 
       if (_person == null) 
       { 
        _person = new PersonManager(_adUserName, _adPassword, client); 
       } 
      } 
     } 
     return _person; 
    } 
} 

を(PersonManagerコンストラクタにこれら3つの引数は、現在のオブジェクトのプロパティ/フィールドです。) このコードは完全に動作します(double-lock checkパターン)。

しかし、これはたくさんのコードですが、私は簡単にするために.Net 4.0で新しいLazy<> typeを使用したいと思います。したがって、これらの3つのパラメータは静的ではないため(現在のメソッドのインスタンスオブジェクト)、これは機能しません。 writeupsI've foundのどれもこれに対処していません。これらの値をラムダ式に渡すには何らかの方法が必要ですか? Lazy <>クラスは、空の署名が必要なようです。

答えて

0

(PersonManagerコンストラクタにこれら3つの引数は、現在のオブジェクトに プロパティ/フィールドです。)

コンストラクタは、オブジェクトを初期化するために使用されます。渡すべき引数には、この時点で値が割り当てられません。オブジェクトでこれらの値を適切に初期化する必要がある場合は、初期化時に渡す必要があります。

プロパティをメソッドに変換し、これらの値を静的なGetInstanceメソッドに渡すことはできますが、最初にGetInstanceが呼び出されたときにこれを1回だけ設定します。これはおそらく良い考えではありませんが、それは可能です。 PersonプロパティをMethodに変換し、これらのパラメータを受け入れてコンストラクタを初期化するために使用します。これは、あなたがLazy<T>を使用しないことを意味し、あなたのコード行は増加しますが、より予測可能な振る舞いをします。

+0

あなたが値を持つ、彼らはオブジェクトのコンストラクタ内の値が割り当てられていないオブジェクトについて間違っています。私はnull参照例外を取得していないよ、私はこれらのフィールドが見つかりませんので、コンパイルエラーが表示されます。 私が始めている私の(作業中の)ダブルチェックロックソリューションよりも、あなたが提案していることがどのように優れているか分かりません。 – Arbiter

+0

@Arbiterあなたがそれらを初期化しているコードからはっきりしていませんでした。 KeithSはあなたのために働くべきです。私はパターンを混ぜないという提案をしています。 – sarvesh

3

Lazyがインスタンスプロパティを使用してシングルトンのインスタンスを操作してプロパティを提供する場合はどうでしょうか?これらのフィールドは、私たちがクラス内部から作業しているので(巧妙な)、プライベートにすることもできます。実行中に初めてSingleton.Instanceが参照されるまで、すべてのことが怠惰です。ただし、コードがPersonプロパティを取得しようとする前に、プライベートフィールドに適切な値が設定されていなければなりません。シングルトンがインスタンス化したときに彼らが熱心に読み込まれたら、それは問題ありません。

C# In Depthから借りて、ここにはシングルトンを参照するラムダを使用して初期化された、完全に怠惰なPersonメンバを持つ疑似レイジーシングルトンがあります。

public sealed class Singleton 
{ 
    private static readonly Singleton instance = new Singleton(); 

    // Explicit static constructor to tell C# compiler 
    // not to mark type as beforefieldinit 
    static Singleton() 
    { 
    } 

    private Singleton() 
    { 
     //I HIGHLY recommend you initialize _adusername, 
     //_adpassword and client here. 
    } 

    public static Singleton Instance 
    { 
     get 
     { 
      return instance; 
     } 
    } 

    private static readonly Lazy<IPersonManager> _person = 
     new Lazy<IPersonManager>(() => new PersonManager(Instance._adUserName, Instance._adPassword, Instance.client)); 
    public static IPersonManager Person { get { return _person.Value; } } 

    private object _adUserName; 
    private object _adPassword; 
    private object client; 
} 

public class PersonManager:IPersonManager {} 

public interface IPersonManager{} 

EDIT:あなたはIoCのを持っている場合は、IoCのを使用しています。現在、パターンを混合しようとしています。ランタイムルールを使用してインスタンスクラスをシングルトンに「昇格」するのにIoCを使用していますが、このフォックスシングルトンのインスタンススコープのデータフィールドに基づいてコンパイラが強制する遅延静的プロパティをインスタンス化しようとしています。これは単に動作しません

IoCになったら、すべての依存関係を登録して注入する必要があります。 PersonManagerをNinjectでIPersonManagerの実装として登録し、次にIPersonManagerを生成するFuncを与えることができるメインシングルトンDataAdapterのコンストラクタを作成します。通常、この目的のためにカスタム関数を定義できます。この場合、IoCを使用して、コンテナに保持されている単一のDataAdapterインスタンスから必要なインスタンスデータを提供します。

注意:これらのデータフィールドは、重大な醜悪な反射を避けるために、公に読めるようになっている必要があります。フィールドを読み取り専用フィールドまたは取得専用プロパティとして定義して、ユーザーがそれらを改ざんするのを防ぐことができますが、消費者はそれらを見ることができます。

EDIT 2:は、ここで私は念頭に置いていたものです:

//in your Ninject bindings: 
kernel.Bind<DataAdapter>().ToSelf().InSingletonScope(); 
kernel.Bind<PersonManager>().ToSelf().InSingletonScope(); 
//to bind the interface 
kernel.Bind<IPersonManager>() 
    .ToMethod(c =>{ 
     var adapter = kernel.Get<DataAdapter>(); 
     //this is why these fields would have to be public 
     var arg1 = new ConstructorArgument("adUserName", adapter._adUserName) 
     var arg2 = new ConstructorArgument("adPassword", adapter._adPassword) 
     var arg3 = new ConstructorArgument("client", adapter.client) 
     //the names of the arguments must match PersonManager's constructor 
     c.Kernel.Get<PersonManager>(arg1, arg2, arg3); 
    }); 

//now in your DataAdapter, specify a constructor like this, and Ninject will provide: 

public DataAdapter(Func<IPersonManager> personFunc) 
{ 
    //_person should obviously not be instantiated where it's defined in this case 
    _person = new Lazy<IPersonManager>(personFunc); 
} 
+0

良い考えですが、それは私にとってはうまくいかないでしょう。私はこのような静的なプロパティを使って 'Singleton'を実装していません、それは単一オブジェクトとしてninjectによって注入されています。この場合の「シングルトン」がシングルトンではなく、通常のインスタンスメンバーであれば、どうしますか? – Arbiter

+0

@Arbiter:編集を参照してください。 – KeithS

+0

'Singleton'は現在コンストラクタを持っています(' client'オブジェクトは接続文字列なしでは初期化できません)。私がコンストラクタを取り除くと、コンストラクタインジェクションの代わりにプロパティインジェクションを使用するようにインジェクションを修正する必要があります.Lazy <>クラスを使用するために飛び越える多くのフープがあります。私はそれがこのための適切なツールではないと思っています。 – Arbiter

関連する問題