0
public interface ICloneable<T>
{
    T Clone();
}

public Foo: ICloneable<Foo>
{
    public Foo Clone()
    { 
       //blah
    }
}

Tインターフェイスを実装する型に制約する方法はありますか? (Fooこの場合)。それ自体のインスタンスを返すように実装するものを強制しICloneable、それが空想する任意の型を強制しないとよいでしょう。

4

2 に答える 2

0

コード コントラクトを使用してこれを表現できることに注意してください。通常、これは実行時にチェックされますが、コンパイル時に警告が表示される可能性があります (後述の注を参照してください)。

次のようになります。

[ContractClass(typeof(CloneableContract<>))]

public interface ICloneable<out T>
{
    T Clone();
}

[ContractClassFor(typeof(ICloneable<>))]

internal abstract class CloneableContract<T>: ICloneable<T>
{
    public T Clone()
    {
        Contract.Ensures(Contract.Result<object>() != null);
        Contract.Ensures(Contract.Result<object>().GetType() == this.GetType());

        return default(T);
    }
}

次に、次のクラス定義がある場合:

public class GoodFoo: ICloneable<GoodFoo>
{
    public virtual GoodFoo Clone()
    { 
        var result = new GoodFoo();
        Contract.Assume(result.GetType() == this.GetType());
        return result;
    }
}

public class BadFoo: ICloneable<object>
{
    public object Clone()
    {
        return new object(); // warning : CodeContracts: ensures unproven: Contract.Result<object>().GetType() == this.GetType()
    }
}

public class AlsoBad: GoodFoo
{
    public override GoodFoo Clone()
    {
        return new GoodFoo(); // warning : CodeContracts: ensures unproven: Contract.Result<object>().GetType() == this.GetType()
    }
}

これは実行時に問題なく動作します:

var good = new GoodFoo();
good.Clone();

これらはランタイム コード コントラクト エラーを引き起こします。

var bad = new BadFoo();
bad.Clone();

var alsoBad = new BadFoo();
alsoBad.Clone();

コンパイル時に警告が表示される場合あることに注意してください。

Code Contracts Static Checking の完全なコンパイルを実行するClone()と、 forclass BadFooおよびの実装について「ensures unproven」に関する警告が表示されclass AlsoBadます。

が実装されているGoodFoo.Clone()ため、警告はありません。Contract.Assume(result.GetType() == this.GetType());

ただし、コード コントラクトの静的チェックは (私の意見では) 時折チェックする以外にはまだ遅すぎますが、マイレージは異なる場合があります...

于 2014-06-23T11:11:35.317 に答える