9

コード コントラクトを使用するコードをコンパイルすると、理解できない非常に奇妙なエラーが発生します。

[ContractInvariantMethod]
private void ObjectInvariant()
{
    Contract.Invariant(
        this.isSubsidiary ||
        this.parentCompanyId == default(Guid));
}

次のエラーで失敗します。

不正な契約。メソッド '<ProjectName>.ObjectInvariant' での代入後に不変が見つかりました。

コードが次のように変更された場合:

[ContractInvariantMethod]
private void ObjectInvariant()
{
    Contract.Invariant(
        this.isSubsidiary ||
        this.parentCompanyId == Guid.Empty);
        // Noticed the Guid.Empty instead of default(Guid)?
}

それはうまくコンパイルされます。

私の何が問題なのdefault(Guid)ですか?

4

1 に答える 1

6

このために生成された IL:

Console.WriteLine("{0}, {1}", default(Guid), Guid.Empty);

は:

    .locals init (
        [0] valuetype [mscorlib]System.Guid CS$0$0000)
    L_0000: nop 
    L_0001: ldstr "{0}, {1}"
    L_0006: ldloca.s CS$0$0000
    L_0008: initobj [mscorlib]System.Guid
    L_000e: ldloc.0 
    L_000f: box [mscorlib]System.Guid
    L_0014: ldsfld valuetype [mscorlib]System.Guid [mscorlib]System.Guid::Empty
    L_0019: box [mscorlib]System.Guid
    L_001e: call void [mscorlib]System.Console::WriteLine(string, object, object)

これは次のようなものに対応します:

Guid CS$0$0000 = new Guid();
Console.WriteLine("{0}, {1}", CS$0$0000, Guid.Empty);

Code Contracts は IL で直接動作するため、2 番目のバージョンのようなものを記述したと見なされます。リライターは、コントラクトの前に変数に代入することは許可されていないと言っているため、エラーが発生します。

ただし、これは機能しないため、奇妙です。

var x = new Guid();
Contract.Invariant(
    this.isSubsidiary ||
    this.parentCompanyId == x);

これはそうですが、明らかに「不変式の前の代入」です!

var x = Guid.Empty;
Contract.Invariant(
    this.isSubsidiary ||
    this.parentCompanyId == x);

彼らは実際にこのようないくつかの割り当てを許可するようにチェッカーを変更したと思いますが(使いやすさのために)、すべてのケースを許可していません...これが意図されているかどうかは私の知識を超えています。

これはCode Contracts フォーラムで報告したいと思います。バグの可能性があります。

于 2010-08-30T01:05:01.963 に答える