2

DataAdapterサイトによってシングルトン オブジェクトとしてインスタンス化されるクラスがあります。そのクラスには、遅延シングルトンにしたい Person プロパティがあります。これを実現するコードは次のとおりです。

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 つの引数は、現在のオブジェクトのプロパティ/フィールドです。) このコードは完全に機能します (二重ロック チェックパターンです)。

ただし、これは大量のコードです。.Net 4.0の新しいLazy<> 型を利用して、よりシンプルにしたいと考えています。そこで、コードを次のように変更します。

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

しかし、これら 3 つのパラメーターは静的ではない (現在のメソッドのインスタンス オブジェクトである) ため、これは機能しません。私が見つけ書き込み はどれもこれに対処していません。これらの値をそのラムダ式に渡す方法が必要ですか? Lazy<> クラスは、空の署名を想定しているようです。

4

2 に答える 2

3

さて、レイジーがインスタンスプロパティを使用してシングルトンのインスタンスと連携し、プロパティを提供した場合はどうなるでしょうか。これらのフィールドは、クラス内から操作しているため(賢い)、プライベートのままにすることができ、実行中に初めてSingleton.Instanceが参照されるまで、すべてが怠惰になります。ただし、コードがPersonプロパティを取得しようとする前に、プライベートフィールドに適切な値を設定する必要があります。シングルトンがそれ自体をインスタンス化するときにそれらが熱心にロードされる場合、それは問題ありません。

C#からの借用深さでは、シングルトンを参照するラムダを使用して初期化された完全に遅延した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{}

編集: IoCをお持ちの場合は、IoCを使用してください。現在、パターンを混合しようとしています。IoCを使用して、ランタイムルールを使用してインスタンスクラスをシングルトンに「プロモート」していますが、このフェイクシングルトンのインスタンススコープのデータフィールドに基づいて、コンパイラが適用する遅延静的プロパティをインスタンス化しようとしています。これは単に機能しません

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

警告:これらのデータフィールドは、深刻な醜い反射を避けるために、公に読み取り可能である必要があります。フィールドを読み取り専用フィールドまたは取得専用プロパティとして定義して、ユーザーによる改ざんを防ぐことができますが、コンシューマーはそれらを見ることができます。

編集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);
}
于 2012-02-15T17:12:56.223 に答える
0

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

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

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

于 2012-02-15T17:05:05.533 に答える