白猫のメモ帳

C#とかJavaとかJavaScriptとかHTMLとか機械学習とか。

C#のジェネリックでワイルドカードが使えないのはどうすればいいの?

こんにちは。

今年度も残すところ一ヶ月になりましたね。
いやはやあっという間です。

今回はC#ジェネリックについて。
最初に書いておきますが、解決には至りません。単純な疑問です。

便利なはてな

まずはJavaでこんなクラスを作って、

abstract class HogeBase {
}
class Hoge1 extends HogeBase {
}
class Hoge2 extends HogeBase {
}

このHogeBaseのインスタンスを型を意識する形でFugaクラスで内包しようとすると、

class Fuga<T extends HogeBase> {
    T hoge;
}

まぁこうなりますよね。
で、更にこのFugaクラスをもうT型を意識しなくていい形でPiyoクラスで内包しようとすると、

class Piyo {
    Fuga<? extends HogeBase> fuga;
}

こんな感じでワイルドカードが使えます。

はてなはどこへいった

同じことをC#でやりたいので、

abstract class HogeBase
{
}
class Hoge1 : HogeBase
{
}
class Hoge2 : HogeBase
{
}

こうなって、

class Fuga<T> where T : HogeBase
{
    T hoge;
}

ワイルドカードがないので親の型をそのまま入れる感じになるのでしょうか?

class Piyo
{
    //Fuga<?> fuga;                     // ワイルドカードかけない
    //Fuga<T> fuga where T : HogeBase;  // でもこんな文法もない
    Fuga<HogeBase> fuga;                // しょうがないので親の型にしておく?
}

再帰ジェネリックを使うと

HogeBaseを再帰ジェネリッククラスにしてみます。
こうするとHogeBase型から派生クラスのインスタンスとかが作れて便利なことがあります。

abstract class HogeBase<T> where T : HogeBase<T>
{
}
class Hoge1 : HogeBase<Hoge1>
{
}
class Hoge2 : HogeBase<Hoge2>
{
}

で、こうなって、

class Fuga<T> where T : HogeBase<T>
{
    T hoge;
}

あれ、どうやっても無理なのでは…。
どこまでいってもクラスジェネリックをつけなくてはならないとか辛すぎです。

class Piyo
{
    //Fuga<?> fuga;                     // ワイルドカードかけない
    //Fuga<T> fuga where T : HogeBase;  // でもこんな文法もない
    //Fuga<HogeBase<?>> fuga;           // 親の型にすらワイルドカードが必要になってしまった
}

こうやって、特に意味のないインタフェース作らないとだめですか?

interface IFuga { }

class Fuga<T> : IFuga where T : HogeBase<T>
{
    T hoge;
}

class Piyo
{
    IFuga fuga;
}

正解がわからないー!!