49186


抽象クラス `Super` を継承した `Sub` クラスがあります。  
`Sub.All` プロパティで `Sub.One` と `Sub.Two` のインスタンスを取得したいです。

[code]

    abstract class Super<T> where T : Super<T>
    {
        private readonly int value;
        private static List<T> list = new List<T>();
    
        public static List<T> All { get { return list; } }
    
        protected Super(int value)
        {
            this.value = value;
            list.Add((T)this);
        }
    }
    
    class Sub : Super<Sub>
    {
        public static Sub One = new Sub(1);
        public static Sub Two = new Sub(2);
    
        private Sub(int value)
            : base(value)
        {
        }
    }
    
[/code]

次のようにすれば `Sub` の静的コンストラクタが実行されるので、実現できることは理解しています。1 行目がない場合でも実現できる方法が知りたいです。

[code]

    var instance = Sub.One; // これがなくても実現してほしい
    var all = Sub.All; // Sub.One と Sub.Two のインスタンスが格納されていてほしい
    
[/code]


CC BY-SA 4.0
2018-10-11T04:53:38.590
49176
2018-10-11T07:50:23.990
28215
question
c#
static プロパティを初期化したい


綺麗な解法ではないことは自覚しつつ...
下記コードのように子クラス`Sub`で親クラス`Super<Sub>`のプロパティを“隠ぺい(hiding)”してしまえば、お望みの挙動が得られるようです。

[code]

    class Sub : Super<Sub>
    {
        public static Sub One = new Sub(1);
        public static Sub Two = new Sub(2);
    
        new public static List<Sub> All { get { return Super<Sub>.All; } }
    
        // (略)
    }
    
[/code]

<https://wandbox.org/permlink/W2hoFpM3GqF4Z0v1>

C#言語では、“該当クラスへアクセス”されたタイミングでstaticメンバの初期化が行われます。このクラス`Sub`へアクセス判定が（少なくとも私には）直感的ではなく、親クラスから継承しているプロパティ(`Super<T>.All`)アクセスでは判定外となる仕様のようです。前掲の解決策では、子クラス自身でプロパティ(`Sub.All`)をあえて再定義し、その内部処理は親クラスへ単純委譲しています。


CC BY-SA 4.0
2018-10-11T07:29:34.860
49183
2018-10-11T07:46:55.430
2018-10-11T07:46:55.430
49
49
49176
answer


>
[code]

>     var all = Sub.All; // Sub.One と Sub.Two のインスタンスが格納されていてほしい
>  
[/code]

ソースコード上は`Sub.All`と記述していますが、実体としては`Super<Sub>.All`であり、コンパイル時にそのように解釈されます。そのため、`Sub`静的コンストラクターが実行される理由が存在しません。

やや強引となりますが、`Super`静的コンストラクター内で強制的に`Sub`静的コンストラクターを呼び出すことでしょうか。

[code]

    static Super() {
        System.Runtime.CompilerServices.RuntimeHelpers.RunClassConstructor(typeof(T).TypeHandle);
    }
    
[/code]


CC BY-SA 4.0
2018-10-11T07:50:23.990
49186
2018-10-11T07:50:23.990
4236
49176
answer