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));
    }
}

我只想要一个解释,甚至不是一个解决方案,它是否与 CodeContracts 不直接在源代码上运行但在 IL 上有关?

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) > 0,a > b成立。因此,此示例不适用于您的通用版本,但适用于您的非通用版本:

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

编辑:

显然我完全误解了你在课堂上的意图Assert。你确实可以做这个论坛上推荐的事情。

但是,您不能指望静态检查器能够理解这一点,例如 fromx.CompareTo(y) > 0遵循x > 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 回答