16

オブジェクト プールを実装したときに、同僚がこれを行うのを初めて見ました。彼は、プールされる予定のクラスをパラメーターとしてジェネリック基本クラスに渡しました。この基本クラスは、プーリング コードをレイアウトしました。

奇妙なことに、基本クラスはその子を認識します。これは、すべての通常のケースで悪い習慣と見なされます。ただし、この場合、親は反復的なコードの記述を避けるための技術的なソリューションにすぎません。基本クラスは、他のコードによって参照されることはありません。

この構造の欠点の 1 つは、「基底クラスを焼き尽くす」ことです。階層の途中にジェネリック基本クラスを導入することはできません。この問題はトピックの外にある可能性があります。

以下は考えられる例です。

public abstract class Singleton<T> where T : class
{
    public static T Instance { get; private set; }

    public Singleton()
    {
        if (Instance != null)
            throw new Exception("Singleton instance already created.");
        Instance = (T) (object) this;
    }
}

public class MyClass : Singleton<MyClass>
{
}

改善されたコード:

public abstract class Singleton<T> where T : Singleton<T>
{
    public static T Instance { get; private set; }

    public Singleton()
    {
        if (Instance != null)
            throw new Exception("Singleton instance already created.");
        Instance = (T) this;
    }
}

public class MyClass : Singleton<MyClass>
{
}
4

2 に答える 2

14

いいえ; これはCRTPと呼ばれるよく知られたパターンです。
これは、仮想メソッドの代替として C++ で特に役立ちます。

IComparable<T>およびの .Net フレームワーク内で確認できますIEquatable<T>

堅牢性を高めるには、追加する必要がありますwhere T : Singleton<T>

于 2013-10-08T11:51:26.317 に答える
3

SLaks は正しいです。これは一般に、派生クラスに強く型付けされたコードを基本クラスに提供する場合に便利なパターンです。

また、一般に、ジェネリック型が抽象型から継承する必要があることを示すために、ジェネリック パラメータに型制約を追加します。この制約を追加するための構文は再帰的に見えますが、慌てる必要はありません。再帰的に評価されるのではなく、有効なジェネリック型のみが派生クラスであることを保証するだけです。

たとえば、紅茶とコーヒーのブレンド事業を経営しているとします。コーヒーとコーヒー、紅茶と紅茶をブレンドすることは理にかなっていますが、コーヒーと紅茶をブレンドできないようにする必要があります。ただし、どちらも飲料であるため、同じ方法でモデル化する必要があります。

public abstract class Beverage<T> where T : Beverage<T>
{
    public abstract T Blend(T drink1, T drink2);
}

public class Tea : Beverage<Tea>
{
    public override Tea Blend(Tea drink1, Tea drink2)
    { 
        // Blend tea here.
    }
}
public class Coffee : Beverage<Coffee>
{
    public override Coffee Blend(Coffee drink1, Coffee drink2)
    { 
        // Blend coffee here.  Although coffee is nasty, so
        // why you'd want to is beyond me.
    }
}

CRTP について読むときは、C++ テンプレートは表面的には C# ジェネリックに似ているだけであることを覚えておく価値があります。主な違いは、テンプレートが実質的にコンパイル時に機能するコード生成ツールであるのに対し、C# ジェネリックは実行時にサポートされることです。

さらに、このようなコードを記述すると、可読性が低下する可能性があります。したがって、これが正しいアプローチである場合は間違いなくありますが、解決しようとしている問題について考え、より簡単なアプローチがあるかどうかを確認する必要があります。

于 2013-10-08T12:31:38.600 に答える