コード コントラクトを使用して順序を強制する、不変の順序付き単一リンク リスト クラスを設定しようとしています。この例に要約されるいくつかの問題に遭遇しています。
[Pure, ContractVerification(true)]
public class Hierarchy
{
private readonly object _data;
private readonly Hierarchy _childField;
public Hierarchy() { }
public Hierarchy(object data, Hierarchy childParameter) {
Contract.Requires<ArgumentNullException>(childParameter != null);
_data = data;
_childField = childParameter;
Contract.Assert(HasChild);
Contract.Assert(_childField == childParameter);
Contract.Assert(_childField.Data == childParameter.Data);
Contract.Assert(ChildProperty == _childField);
Contract.Assert(ChildProperty.Data == _childField.Data); //Warning -- CodeContracts: assert unproven
}
public bool HasChild { get { return _childField != null; } }
public object Data {
get {
Contract.Ensures(Contract.Result<object>() == _data);
return _data;
}
}
public Hierarchy ChildProperty {
get {
Contract.Requires<InvalidOperationException>(HasChild);
Contract.Ensures(Contract.Result<Hierarchy>() == _childField);
//un-commenting this line causes the assertion to succeed.
//Contract.Ensures(Contract.Result<Hierarchy>().Data == _childField.Data);
return _childField;
}
}
[ContractInvariantMethod]
private void Invariant() {
Contract.Invariant(HasChild == (ChildProperty != null));
}
}
コード コントラクトは、アサーションを証明できる必要があるように思えますChildProperty.Data == _childField.Data
。以前のアサーションChildProperty == _childField
は成功し、同じオブジェクトに対して純粋なData
プロパティ ゲッターを 2 回呼び出すと、同じ結果が返されます。
と という (成功した) 以前のアサーションにも注意して_childField == childParameter
ください_childField.Data == childParameter.Data
。
上記の 2 番目のコメントで述べたように、問題は事後条件Contract.Ensures(Contract.Result<Hierarchy>().Data == _child.Data);
をChildProperty
ゲッターに追加することで解決されます。必要な作業はこれだけであることに注意してください。この場合、コード コントラクトは、 whenが x と y で getter をx == y
呼び出しても同じ結果が得られることを認識します。Data
この回避策は、この小さな例では問題ありませんが、大規模なクラスの場合、型のプロパティごとに事後条件を追加する必要があるのは面倒です (ややばかげていることは言うまでもありません)。
バグですか?アサーションChild.Data == _child.Data
を証明できるコントラクト アノテーションなどを見逃していませんか? 言い換えれば、問題を解決する他の方法はありますか?