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