1

私はこれを MSDN のCodeContracts フォーラムに投稿しましたが、明らかに誰もこの問題を知りませんし、調べようともしません。

繰り返しのアサートを減らして再利用できるようにしようとしましたが、残念ながらこれはうまくいきません。理由を説明していただけますか?

[ContractVerification(false)]
public static class Assert
{
    [Conditional("DEBUG")]
    public static void GreaterThan<T>(T value, T lowerBound) where T : IComparable<T>
    {
        Contract.Ensures(value.CompareTo(lowerBound) > 0);
    }

    [Conditional("DEBUG")]
    public static void GreaterThanOrEqual<T>(T value, T lowerBound) where T : IComparable<T>
    {
        Contract.Ensures(value.CompareTo(lowerBound) >= 0);
    }

    [Conditional("DEBUG")]
    public static void LessThan<T>(T value, T upperBound) where T : IComparable<T>
    {
        Contract.Ensures(value.CompareTo(upperBound) < 0);
    }

    [Conditional("DEBUG")]
    public static void LessThanOrEqual<T>(T value, T upperBound) where T : IComparable<T>
    {
        Contract.Ensures(value.CompareTo(upperBound) <= 0);
    }

    [Conditional("DEBUG")]
    public static void NotNull(object value)
    {
        Contract.Ensures(value != null);
    }

    [Conditional("DEBUG")]
    public static void NotNullOrEmpty(string value)
    {
        Contract.Ensures(!string.IsNullOrEmpty(value));
    }

    [Conditional("DEBUG")]
    public static void True(bool value)
    {
        Contract.Ensures(value);
    }

    [Conditional("DEBUG")]
    public static void False(bool value)
    {
        Contract.Ensures(!value);
    }

    [Conditional("DEBUG")]
    public static void InRange<T>(T value, T lowerBound, T upperBound, ExclusionMode exclusionMode = ExclusionMode.None) where T : IComparable<T>
    {
        Contract.Ensures(((exclusionMode | ExclusionMode.LowerBound) == ExclusionMode.LowerBound ? value.CompareTo(lowerBound) > 0 : value.CompareTo(lowerBound) >= 0) && ((exclusionMode | ExclusionMode.UpperBound) == ExclusionMode.UpperBound ? value.CompareTo(upperBound) < 0 : value.CompareTo(upperBound) <= 0));
    }
}

私はそれを次のように変更しましたが、動作しているように見えますが、明らかに汎用バージョンの方が望ましいです。

[ContractVerification(false)]
public static class Assert
{
    [Conditional("DEBUG")]
    public static void GreaterThan(int value, int lowerBound)
    {
        Contract.Ensures(value > lowerBound);
    }

    [Conditional("DEBUG")]
    public static void GreaterThanOrEqual(int value, int lowerBound)
    {
        Contract.Ensures(value >= lowerBound);
    }

    [Conditional("DEBUG")]
    public static void LessThan(int value, int upperBound)
    {
        Contract.Ensures(value < upperBound);
    }

    [Conditional("DEBUG")]
    public static void LessThanOrEqual(int value, int upperBound)
    {
        Contract.Ensures(value <= upperBound);
    }

    [Conditional("DEBUG")]
    public static void NotNull(object value)
    {
        Contract.Ensures(value != null);
    }

    [Conditional("DEBUG")]
    public static void NotNullOrEmpty(string value)
    {
        Contract.Ensures(!string.IsNullOrEmpty(value));
    }

    [Conditional("DEBUG")]
    public static void True(bool value)
    {
        Contract.Ensures(value);
    }

    [Conditional("DEBUG")]
    public static void False(bool value)
    {
        Contract.Ensures(!value);
    }

    [Conditional("DEBUG")]
    public static void InRange(int value, int lowerBound, int upperBound, ExclusionMode exclusionMode = ExclusionMode.None)
    {
        Contract.Ensures(((exclusionMode | ExclusionMode.LowerBound) == ExclusionMode.LowerBound ? value > lowerBound : value >= lowerBound) && ((exclusionMode | ExclusionMode.UpperBound) == ExclusionMode.UpperBound ? value < upperBound : value <= upperBound));
    }
}

ソースコードではなくILで直接動作するCodeContractsと関係がありますか?

4

1 に答える 1

2

あなたが望むことは完全に可能ですが、それを知っている人は多くありません。まず、コンピューターにアクセスして、プロジェクトC:\Program Files (x86)\Microsoft\Contracts\Languages\CSharpに含めます。ContractExtensions.cs必要ないくつかの属性が含まれています。

次に、ContractAbbreviator属性をメソッドに適用します。プロジェクトの [コード コントラクト] プロパティ ページでデバッグとリリースのコントラクト動作を設定できるため、属性[Conditional("DEBUG")]と属性を削除できます。[ContractVerification(false)]メソッドの開始時にコントラクト メソッドを呼び出す必要があることに注意してください。それ以外の場合はコントラクトを記述します。メソッドに他のコードを入れることはできません。

public static class Assert
{
    [ContractAbbreviator]
    public static void GreaterThan<T>(T value, T lowerBound)
        where T : IComparable<T>
    {
        Contract.Ensures(value.CompareTo(lowerBound) > 0);
    }

    // ...
}

これはあなたの質問に対する回答ですが、問題が解決しない可能性があります。その理由は、静的チェッカーが、 が成り立つときa.CompareTo(b) > 0a > bそれを見ることができないからです。したがって、この例は汎用バージョンでは機能しませんが、非汎用バージョンでは機能します。

static int PlusOne(int value)
{
    #region Contract
    Contract.Requires(value > 0);
    Assert.GreaterThan(value, 0);
    #endregion
    return value + 1;
}

編集:

どうやら私はAssertクラスであなたの意図を完全に誤解していたようです. このフォーラムで推奨されていたことは実際に実行できます。

ただし、静的チェッカーがそれを理解することは期待できませx.CompareTo(y) > 0x > y。理由?これらのメソッドには文字通り何でも入れることができます。例えば:

public int CompareTo(MyType t)
{
    // Implementation not consistent with '>'
    return this.field1 == t.field1 ? -1 : 1;
}

public static operator bool >(MyType left, MyType right)
{
    // Implementation not consistent with CompareTo()
    return left.CompareTo(right) <= 0;
}

あなたも持っていないかもしれませんCompareTo。そのため、静的チェッカーはそれらの間の類似点を確認できません。

于 2012-07-27T11:44:22.410 に答える