2009-04-27 19 views
5

プログラムの開始時に自動的にインスタンス化されるシングルトンを作成したいと思います。私は、「インスタンス化オート」の意味は何C#でシングルトンを自動インスタンス化する

はシングルトンのコードが他のコードによって、すべての呼び出しまたは宣言せずにプログラムの起動時に自分自身をインスタンス化する必要があることです。

これはC#のため、動作しません除いだから私は(何もメインコードなし)プログラムの起動時に「MySingletonインスタンス化」をインスタンス化して書き出すには、以下のような何か...

static class MySingleton 
{ 
    private static MySingleton self = new MySingleton(); 

    protected MySingleton() 
    { 
     System.Console.WriteLine("MySingleton Instantiated"); 
    } 
} 

をお勧めしますクラスの静的メンバーを必要に応じて、つまりアクセスされたときなどにのみ初期化します。

どうすればいいですか?これはできますか?

私はC++(しばらくの間、C++を使用していない)と個人的にこれを行っていないが、私はかなりそれがCで行うことができることを確認して++が、C#のについてはよく分かりません。

何か助けていただければ幸いです。ありがとう。共通から継承するすべてが(時間が経つとして追加することができ、より)私は実際に... は、これらのシングルトンクラスの多くがあるでしょう。このとやりたいと思ってる


、 (抽象)親クラス(別名PClass)。

PCLASSは(そして、理論的にはすべてのシングルトンが自動的にコレクションに追加されます...

をPClassesのコレクション...とコレクションに自分自身を追加するためのコンストラクタです静的メンバを持っているでしょうそれらがインスタンス化されると、ベースのPClassコンストラクタが呼び出され、新しいオブジェクトがコレクションに追加されるため)...コレクションは、どの子(シングルトン)クラスが実装されているか、新しい子(シングルトン)クラス他のコードを変更することなくいつでも追加できます。

残念ながら、私はこの記事で、その結果、私の小さな計画を台無しに...子供(シングルトン)は自分自身をインスタンス化することができません。

私はそれを十分に説明しました。


PS。はい、私はシングルトンとその使用の周りに悪い気持ちがあることを知っています...しかし、それらは時には有用であり、サタン自身がシングルトンを作ったとしても、私の問題がC#で達成できるかどうかを知りたいです。あなたに親切に感謝します。

+2

サタンはシングルトンです。 –

答えて

6

のIoCアプローチは、おそらく最高のですが、私は考えることができる「最善の」ソリューションは反射でファンキーな何かをすることであるということができないとの線に沿って属性:付き

public class InitOnLoad : Attribute 
{ 
    public static void Initialise() 
    { 
     // get a list of types which are marked with the InitOnLoad attribute 
     var types = 
      from t in AppDomain.CurrentDomain.GetAssemblies().SelectMany(a => a.GetTypes()) 
      where t.GetCustomAttributes(typeof(InitOnLoad), false).Count() > 0 
      select t; 

     // process each type to force initialise it 
     foreach (var type in types) 
     { 
      // try to find a static field which is of the same type as the declaring class 
      var field = type.GetFields(System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.NonPublic).Where(f => f.FieldType == type).FirstOrDefault(); 
      // evaluate the static field if found 
      if (field != null) field.GetValue(null); 
     } 
    } 
} 

[InitOnLoad] 
public class Foo 
{ 
    public static Foo x = new Foo(); 

    private Foo() 
    { 
     Console.WriteLine("Foo is automatically initialised"); 
    } 
} 

public class Bar 
{ 
    public static Bar x = new Bar(); 

    private Bar() 
    { 
     Console.WriteLine("Bar is only initialised as required"); 
    } 
} 

あなたのメインメソッドにInitOnLoad.Initialise()の呼び出しを追加しました。

属性を削除することはできますが、不要な型が初期化され、不必要にメモリを消費することがあります(上記のコードのBarなど)。

これは、Initializeをもう一度呼び出さない限り、動的にロードされるアセンブリに含まれる型を処理しないことにも注意してください。ただし、あなたの質問(「プログラムの開始時に自動インスタンス化」)あなたのための問題のように聞こえる。

+0

質問の更新後、属性を祖先型チェックで置き換えることができます。 Initializeコードは、基本クラスの静的コンストラクタに移動できます。アプリケーションで基本クラスが参照されるとすぐに、すべての先祖もロードされます。 – Richard

+0

私はReflectionについて聞いたことがありますが、それを使用していない...これがこのようなものに使用できるかどうか疑問に思っていた... これは最高のソリューションのように思えます。私は何をしたいのですか?反射で私はこれが達成できると思います。ありがとう。 – devlop

5

.NETモジュールは、理論的には(IIRC)負荷などモジュールに反応することができるが、これは、C#を介して利用できません。いくつかのフレームワーク(ASP.NETなど)では、ハンドラまたはglobal.asax.csを介してハッキングするなどの設定を介して使用できるフックがありますが、通常のC#アプリケーション(コンソール、winformなど)では、手動で起動します。たとえば、Mainエントリポイントをホストするクラスの静的コンストラクタが呼び出されます。

ので:ユースケースは、ここでは何ですか?遅延読み込みのアプローチはいつOKですか?

+0

ユースケースを追加するために投稿を編集しました。 – devlop

2

私は、これはMainから何もせずに可能である疑い。クラスにstatic MySingleton() {}を追加しても、それを使用しないとインスタンス化が保証されるわけではありません。

0

私はあなたが望むものが.Netフレームワークで可能であるとは思わない。基本的には、ランタイムのようなものが型を通知したり、アプリケーションがロードされ実行されているか、あるいはそのようなメカニズムを提供する、あらかじめ定義された静的メソッドを呼び出す必要があります。オーバーヘッドについて考える。ランタイムが保証するのは、プログラムのメインエントリメソッドを自動的に呼び出すことだけです。それでおしまい。そこに物事を設定して初期化することはできますが、それについては何も自動ではありません。あなたは依然として明示的に物事をフックし、メソッド呼び出しを行っています。

+0

私はそれが可能ではないと思っています...しかし、それはすべきです! 私はそれがC++でできると確信していますが、私は実際にやっていません...そして、明らかにC#はC++ではありませんが、このタイプのことはC#ではできません。 – devlop

+0

私はそれがC++でも可能だとは思っていません。私はMark Gravellが述べたようにdllがロードされ、アンロードされ、スレッドが添付されるたびにWindowsが呼び出す各dllに標準コールバックがあることを覚えていますが、明示的にシングルトンを初期化する必要があります。さらに、.NETでは、これらのコールバックにアクセスすることはできません。 1つの可能性は、.NETランタイムをホストする独自のブートストラップを持つことです。次に、あなたはCLRホスティングapisまたはいくつかのトリックを使用して、何をしたいのですか?なぜですか?私はあなたのデザインとこの要件の必要性を再考すべきだと思います。 –

1

基本的には、アセンブリを読み込むたびに.NET Frameworkで関数を呼び出すようにしています。その機能は、PClassインスタンスのレジストラになります。

C#にはDllMainがありません。これをシミュレートするには、アセンブリレベルの属性とメインメソッドにいくつかのコードを用意します。このコードは、アセンブリがロードされるたびにリッスンします。属性には、 "DllMain"エントリポイントが指定されているか、またはあなたのPCIass継承クラスを指している可能性があります。

1

実際には、通常実装されているように、これは実際にシングルトンパターンではないことを指摘してください。ここではC#で、通常の(簡体字)の実装は、(簡潔にするためにスレッドの安全性のようなものは含まない)です。

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

// private ctor 
Singleton() {} 

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

あなたのコードからこの行は、コンパイルさえべきではありません!

protected MySingleton() 

私はあなたのユースケースについて質問した人に同意します。それは知っていると良いでしょう。 =)

+0

あなたはデモンストレーションのように通常はインスタンスアクセサーを持っていますが、私の問題は他のコードがシングルトンに直接アクセスしないようにすることです...ただインスタンス化するだけです。アクセサー。 また、ユースケースの説明を追加するために私の質問を編集しました。 – devlop

+0

ところで、保護されたコンストラクタで何が問題なのですか。それはうまくコンパイルされます。 – devlop

+0

静的クラスに(任意のアクセスレベルの)ctorを追加すると、コンパイラエラー( "静的クラスはインスタンスコンストラクタを持つことができません")が表示されます。 – Garrett

4

あなたがしようとしていることに基づいて、真のシングルトンのアイデアを削除し、代わりにIoCライブラリを使用します。

Structure Map、Castle Windsor、Ninject、Autofacをチェックしてください。

これにより、IoCライブラリを介して、必要な数だけシングルトンとしてクラスを作成することができますが、単純な古いクラスです。

シングルトンは、アプリケーションのテスト容易性(単体テストによる)が本当に混乱するという問題があります。

「Singleton Considered Harmful」でGoogle検索を行うと、さらに多くの参照が表示されます。

また、単純なクラスファクトリ/メソッドファクトリパターンを使用することもできます。クリスが言及した

+0

私はIoCライブラリに精通していません...そして私のニーズに対して、私はもっと複雑に思えますか? 現在、私は基本的にファクトリメソッドを実行しています。しかしそれはいいものではありません。 – devlop

+0

IoCはそれほど複雑ではありません。追加のボーナスは、IoCが自動依存性注入のためにアプリケーションの残りの部分も助けることができるということです。この問題に使用しなくても、IoCは検討する価値があります。 –

0

「PCLASSはPClassesのコレクションです静的メンバを持っているでしょう...」

は、リフレクションで簡単に行うことができる何かのように聞こえます。起動時に実行されるコードは必要ありません。必要な時にいつでもこれらのクラスのリストを作成することができます。

インスタンスプロパティを最初に読み込んだときにリストを一度ロードすると、その時点でロードされているすべてのアセンブリが表示されます(同じアセンブリ内でのみ見たい場合はこれを少し簡略化できます)。 PClassですが、あなたが調べたいアセンブリを指定していません)、リストにPClassの子孫(PClass自体ではない)のインスタンスを1つ追加します。各PClassの子孫にはパラメータのないコンストラクタが必要ですが、クラスコンストラクタは必要ありません。

public class PClass 
{ 
    private static List<PClass> m_instances; 
    public static IList<PClass> Instances 
    { 
     get 
     { 
      if (m_instances == null) 
       m_instances = LoadInstanceList(); 
      return m_instances; 
     } 
    } 
    private static List<PClass> LoadInstanceList() 
    { 
     foreach (var assembly in AppDomain.GetAssemblies()) 
     { 
      foreach (var type in assembly.GetTypes()) 
      { 
       if (type.IsAssignableTo(typeof(PClass)) && type != typeof(PClass)) 
        m_instances.Add(Activator.CreateInstance(type)); 
      } 
     } 
    } 
} 
+0

ありがとう、リチャードは最初にReflectionのものを持っていたので、彼に小切手を渡した。とにかく答えてくれてありがとう。 ここで複数のチェックを行うことはできませんか? – devlop

+0

Activator.CreateInstanceには、デフォルトのパブリックコンストラクタが(少なくともデフォルトで)必要です。与えられたシングルトンの例では与えられていないので、私はリフレクションを使って宣言クラスと同じ型のフィールドを見つけ、そのフィールドの値を取得します。 – Richard

関連する問題