4

ジェネリック値を定義するジェネリック インターフェイスと、次のようなコピー コンストラクターがあるとします (ICloneable を置き換えます)。

// T: type of value to hold, TU: type of the class itself
interface ICopyable<T,TU> where TU: ICopyable<T,TU> {
    T Value { get; set; }
    TU Copy();
}

これは、次のようなブール値ホルダーによって実装できます。

class BooleanHolder : ICopyable<Boolean, BooleanHolder> {
    public BooleanHolder Copy() { 
        return new BooleanHolder(){ Value = Value }; 
    }
}

別の ICopyable を保持するデコレータ クラスをどのように定義しますか? 私のうまくいかないアイデアは次のとおりです。

class DecoratingHolder<T,TU> : ICopyable<ICopyable<T,TU>, DecoratingHolder<T,TU>> {
    public DecoratingHolder<T,TU> Copy {
        // won't compile as Value is of type T and not of type ICopyable<T,TU> 
        // as I expected - why is that?
        return new DecoratingHolder<T,TU>(){ Value = Value.Copy };
    }
}

Copytype の値もコピーするように呼び出したことに注意してくださいICopyable<T,TU>。これは、ディープ コピーを確実にするための意図的なものです。

では、この構造を機能させるには何を変更する必要がありますか?

4

2 に答える 2

3

制約を追加する必要があるかもしれません。あなたはそれを定義しICopyable<T, TU> where TU : ICopyable<T, TU>ますが、あなたのでは、そのようにDecoratingHolder明示的に制約することは決してありません。TUDecoratingHolder

より具体的には、次の部分だと思います。

class DecoratingHolder<T,TU> : ***ICopyable<ICopyable<T,TU>***

それが問題の原因です。ICopyable<T,TU>タイプを定義しTUていますが、 に制約されていませんICopyable<T, TU>(残りのクラス宣言/継承からそれを推測できるかもしれませんが、コンパイラはそうしません)制約を追加すると、コンパイラはそれが互換性のある型であることを認識します。ValueICopyable<T,TU>

これは私にとっては問題なくコンパイルされます(提供された疑似コードで他のいくつかの小さな問題を修正する必要がありました):

class DecoratingHolder<T,TU> : ICopyable<ICopyable<T,TU>, DecoratingHolder<T,TU>> 
    where TU : ICopyable<T,TU>
{
    public ICopyable<T,TU> Value { get; set; }

    public DecoratingHolder<T,TU> Copy() {
        return new DecoratingHolder<T, TU>(){ Value = Value };
    }
}

編集:振り返ってみると、その制約が必要ICopyableですか? とにかく、発信型をすでに一般的に定義しているため、あまり効果がないようです。ICopyable<T, TU>何らかの理由で返されるという事実に依存するコードが他の場所にない限り(厳密に型指定されたTUorBooleanHolderまたはを返すため、本質的にいずれにせよDecoratingHolder)、それをダンプすることを検討してください。

interface ICopyable<T,TU>
{
    T Value { get; set; }
    TU Copy();
}

class BooleanHolder : ICopyable<Boolean, BooleanHolder> 
{
    public bool Value { get; set; }
    public BooleanHolder Copy() { 
        return new BooleanHolder(){ Value = Value }; 
    }
}

class DecoratingHolder<T,TU> : ICopyable<ICopyable<T,TU>, DecoratingHolder<T,TU>> 
{
    public ICopyable<T,TU> Value { get; set; }

    public DecoratingHolder<T,TU> Copy() {
        return new DecoratingHolder<T, TU>(){ Value = Value };
    }
}

編集:ディープコピーを必要とするコメントから、制約を保持し(必要になります)、呼び出しCopyますValue(申し訳ありませんが、その詳細を見逃していたに違いありません)

class DecoratingHolder<T,TU> : ICopyable<ICopyable<T,TU>, DecoratingHolder<T,TU>> 
    where TU : ICopyable<T,TU>
{
    public ICopyable<T,TU> Value { get; set; }

    public DecoratingHolder<T,TU> Copy() {
        return new DecoratingHolder<T, TU>(){ Value = Value.Copy() };
    }
}

Copy特定のクラスのメソッドは、ディープ コピーを確実に実行する必要があります。(フレームワークでそれらをディープ コピーにする必要があり、実装で誤ってシャローを実行したくない場合は、名前を に変更Copyすることをお勧めします)DeepCopy

于 2012-11-24T14:12:40.950 に答える
0

キャストが私のために働いた:

    public DecoratingHolder<T, TU> Copy()
    {
        return new DecoratingHolder<T, TU>() { Value = (ICopyable<T, TU>)Value.Copy() };
    }

TUこの文脈では、コンパイラはそれを確立するまでには至らずICopyable<T, TU>、同じことだと思います。

于 2012-11-24T14:12:47.767 に答える