ジョン・スキートによるシングルトンの説明


214
public sealed class Singleton
{
    Singleton() {}

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

    class Nested
    {
        // Explicit static constructor to tell C# compiler
        // not to mark type as beforefieldinit
        static Nested() {}
        internal static readonly Singleton instance = new Singleton();
    }
}

現在のアプリケーションにJon SkeetのシングルトンパターンをC#で実装したいと思います。

コードに2つの疑問があります

  1. ネストされたクラス内の外部クラスにアクセスするにはどうすればよいですか?というのは

    internal static readonly Singleton instance = new Singleton();

    閉鎖と呼ばれるものはありますか?

  2. このコメントを理解できません

    // Explicit static constructor to tell C# compiler
    // not to mark type as beforefieldinit
    

    このコメントは私たちに何を示唆していますか?


12
笑少し心配だと思っていた笑...ジョンノーランが違うことが判明
ジョンアントニーダニエルノーラン

14
2つのことが一般的に受け入れられています。東から昇る太陽とジョンスキートは常に正しいです。しかし、前者についてはまだ
わかり

2
@ thepirat000-彼がSO / Metaの参加者だけだった場合、私は反対するかもしれませんが、彼は実際のプログラミングの世界で実際に合法である可能性がある十分な影響力を持っています-誰かがいつかそれを作成したと思います。
コードジョッキー

8
この質問の分類法はmetaで議論されています。
BoltClock

回答:


359
  1. いいえ、これはクロージャとは関係ありません。ネストされたクラスは、ここのプライベートコンストラクターを含む、外部クラスのプライベートメンバーにアクセスできます。

  2. beforefieldinitに関する私の記事を読んでください。no-op静的コンストラクターが必要な場合と不要な場合があります。これは、必要な遅延保証によって異なります。.NET 4 実際の型初期化セマンティクスを多少変更することに注意してください(まだ仕様内ですが、以前よりも時間がかかります)。

あなたがでください本当にかかわらず、このパターンがありますか?あなたは逃げることができないと確信しています:

public sealed class Singleton
{
    private static readonly Singleton instance = new Singleton();
    public static Singleton Instance { get { return instance; } }

    static Singleton() {}
    private Singleton() {}
}

12
@Anindya:いいえ、それで結構です。あなたは:)のに文句をメールジェットブレーンズにしたいかもしれません
ジョンスキート

2
@JonSkeet、私はこれについてJetBrainsに懸念を表明しました(#RSRP-274373)。彼らが何を考え出すことができるか見てみましょう。:)
Anindya Chatterjee

3
@ムーンズ:そうではありません。シングルトンは、AppDomainの存続期間中存続します。
Jon Skeet

2
@JonSkeet Lazy<T>マジックのBeforeFieldInit副作用のために静的コンストラクタを宣言する必要がないように使用しない理由はありますか?
Ed T

3
FieldBeforeInitであるMahaBharataからMicrosoft
アミット・クマールゴーシュ

49

質問(1)に関して:ジョンからの答えは正しいです。なぜなら、彼はそれをパブリックまたは内部にしないことによってクラスを「ネストされた」プライベートに暗黙的にマークするからです:-)。'private'を追加して明示的に行うこともできます。

    private class Nested

質問(2)について:基本的に、beforeinitfield型の初期化に関する投稿でわかっているのは、静的コンストラクターがない場合、ランタイムはいつでも(ただし使用する前に)初期化できるということです。静的コンストラクターがある場合、静的コンストラクター内のコードはフィールドを初期化する可能性があります。つまり、ランタイムがフィールドを初期化できるのは、型を要求したときだけです。

したがって、使用する前にランタイムがフィールドを「プロアクティブに」初期化したくない場合は、静的コンストラクターを追加します。

どちらの方法でも、シングルトンを実装する場合は、ランタイムが変数を初期化する必要があると判断したときではなく、できるだけ遅延して初期化するか、おそらく気にしないでください。あなたの質問から、私はあなたが彼らをできるだけ遅くしたいと思います。

これは、シングルトンに関するJonの投稿に出会い、IMOがこの質問の根本的なトピックです。ああ、疑問:-)

彼が「間違っている」とマークした彼のシングルトン#3は実際には正しいことを指摘しておきます(ロックは自動的に終了時にメモリバリアを意味するため)。また、インスタンスを2回以上使用する場合は、シングルトン#2より高速である必要があります(シングルトンのポイントは多かれ少なかれです:-))。したがって、本当に遅延シングルトン実装が必要な場合は、おそらくそれを使用します-(1)何が起こっているのかをコードを読み取る誰にとっても非常に明確であり、(2)何が起こるかを知っているという単純な理由例外あり。

ご参考までに:シングルトン#6を使用することはありません。デッドロックや例外を伴う予期しない動作が発生しやすいためです。詳細については、lazyのロックモード、特にExecutionAndPublicationを参照してください。


62
Regarding question (1): The answer from Jon is correct ...ジョンスキートは常に正しい....
Noctis

72
ジョンスキートがすでに回答しているジョンスキートの質問について回答を試みるための追加ポイント。
valdetero 2015年

8
@valdeteroハハハ。これ...ははは+1
akinuri
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.