さて、レイジーがインスタンスプロパティを使用してシングルトンのインスタンスと連携し、プロパティを提供した場合はどうなるでしょうか。これらのフィールドは、クラス内から操作しているため(賢い)、プライベートのままにすることができ、実行中に初めて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);
}