この質問が長すぎると思われる場合は申し訳ありません。質問する前に、それがどこから来ているのかを示す必要があります。
設定:
次の不変タイプが与えられますRectangle
:
class Rectangle
{
public Rectangle(double width, double height) { … }
public double Width { get { … } }
public double Height { get { … } }
}
…それから型を導き出すことは完全に合法のようですSquare
:
using System.Diagnostics.Contracts;
class Square : Rectangle
{
public Square(double sideLength) : base(sideLength, sideLength) { }
[ContractInvariantMethod]
void WidthAndHeightAreAlwaysEqual()
{
Contract.Invariant(Width == Height);
}
}
…派生クラスは、それ自体の不変条件が違反されないようにすることができるためです。
Rectangle
しかし、私が可変にするとすぐに:
class Rectangle
{
public double Width { get; set; }
public double Height { get; set; }
…
}
…との独立したセッターを持つべきではないSquare
ので、私はもはやそれから派生するべきではありません。Square
Width
Height
質問:
Square
可変Rectangle
クラスから派生するとすぐにコントラクト違反を警告するように、コードコントラクトで何ができますか?できれば、コードコントラクトの静的分析により、コンパイル時にすでに警告が表示されます。
言い換えれば、私の目標は、コードコントラクトを使用して次のルールをエンコードすることです。
Width
およびのは、互いに独立して変更Height
することができます。Rectangle
Width
とHeight
のはSquare
互いに独立して変更することはできず、そもそもそれは意味がありません。
…そして、これらのルールが「衝突」するたびにコードコントラクトが気付くような方法でそれを行います。
私がこれまで考えてきたこと:
1.不変条件をRectangle
:に追加します
class Rectangle
{
…
[ContractInvariantMethod]
void WidthAndHeightAreIndependentFromOneAnother()
{
Contract.Invariant(Width != Height || Width == Height);
}
}
このアプローチの問題は、不変条件が「幅と高さは等しい必要はありませんが、等しくなる可能性があります」と正しく述べている一方で、(1)トートロジーであるため、(2)それがWidth == Height
派生クラスの不変条件よりも制限が少なくなりSquare
ます。おそらく、コードコントラクトがそれを見る前に、コンパイラによって最適化されているのかもしれません。
Rectangle
2.のセッターに事後条件を追加します。
public double Width
{
get { … }
set { Contract.Ensures(Height == Contract.OldValue(Height)); … }
}
public double Height
{
get { … }
set { Contract.Ensures(Width == Contract.OldValue(Width)); … }
}
これにより、派生クラスが変更されるたびにSquare
更新Height
されることは禁止され、その逆も同様です。それ自体がからクラスを派生することを妨げることはありません。しかし、それが私の目標です。コードコントラクトに、可変から派生してはならないことを警告してもらうことです。Width
Width
Square
Rectangle
Square
Rectangle