CodeContracts 静的解析ツールと議論しています。
私のコード:
(アスキー版)
ツールはinstance.bar
、null 参照である可能性があることを示しています。私は反対のことを信じています。
誰が正しいですか?どうすればそれが間違っていると証明できますか?
CodeContracts 静的解析ツールと議論しています。
私のコード:
(アスキー版)
ツールはinstance.bar
、null 参照である可能性があることを示しています。私は反対のことを信じています。
誰が正しいですか?どうすればそれが間違っていると証明できますか?
CodeContracts は正しいです。instance.bar = null
メソッドを呼び出す前に設定することを妨げるものは何もありませんBarLength()
。
更新: 問題は、静的フィールドで不変条件がサポートされていないことです。
2 回目の更新:以下に概説する方法は、現在推奨される解決策です。
考えられる回避策は、保持したい不変条件のプロパティを作成するinstance
ことです。Ensure
(もちろん、 を証明するにAssume
はそれらが必要Ensure
です。) これが完了したら、プロパティを使用するだけで、すべての不変条件が正しく証明されるはずです。
このメソッドを使用した例を次に示します。
class Foo
{
private static readonly Foo instance = new Foo();
private readonly string bar;
public static Foo Instance
// workaround for not being able to put invariants on static fields
{
get
{
Contract.Ensures(Contract.Result<Foo>() != null);
Contract.Ensures(Contract.Result<Foo>().bar != null);
Contract.Assume(instance.bar != null);
return instance;
}
}
public Foo()
{
Contract.Ensures(bar != null);
bar = "Hello world!";
}
public static int BarLength()
{
Contract.Assert(Instance != null);
Contract.Assert(Instance.bar != null);
// both of these are proven ok
return Instance.bar.Length;
}
}
コードには、プライベートな静的初期化インスタンスが含まれています。
private static Foo instance = new Foo();
これは、静的メソッドにアクセスする前にインスタンスコンストラクターが常に実行されることを意味するため、確実に初期化されると想定しbar
ていますか?
シングルスレッドの場合、私はあなたが正しいと思います。
イベントのシーケンスは次のようになります。
Foo.BarLength()
Foo
(まだ完了していない場合)instance
のインスタンスを使用したプライベート静的メンバーの静的初期化Foo
Foo.BarLength()
ただし、クラスの静的初期化はアプリ ドメインごとに 1 回だけトリガーされます。また、IIRC では、他の静的メソッドが呼び出される前に完了することを保証するブロックはありません。
したがって、次のシナリオが考えられます。
Foo.BarLength()
Foo
(まだ完了していない場合) が開始されますFoo.BarLength()
Foo
Foo.BarLength()
null
スレッド ベータ:静的メンバーへのアクセスinstance
コントラクト アナライザーは、コードをマルチスレッドで実行したことがないということを知ることはできないため、慎重に行う必要があります。
フィールド「バー」を読み取り専用としてマークすると、静的アナライザーは、ctor の実行後にフィールドが他の値に設定されないことを確認する必要があります。
仰るとおりです。 instance
とbar
両方とも非公開であるため、CodeContracts は がinstance.bar
null に設定されていないことを認識できるはずです。