本文介绍了CodeContracts:重用假设/断言?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已将其发布在 CodeContracts论坛,但显然没有人知道或不愿意对此问题进行调查.

I've posted this on the CodeContracts forum at the MSDN but apparently no one knows or bothers to look into this issue.

我试图减少重复的断言并使其更可重用,但是不幸的是,这不能奏效吗?您能解释为什么吗?

I've tried to reduce the repetitive asserts and make it more reusable but unfortunately this doesn't work can you explain why?

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

我将其更改为以下内容,并且似乎可以使用,但显然更希望使用通用版本.

I changed it to the following and it seems to work but obviously the generic version is more desirable.

[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有关吗?

I just want an explanation not even a solution, does it have to do with CodeContracts not operating directly on the source code but on the IL?

推荐答案

您想要的东西完全可以实现,但是没有多少人知道.首先,在计算机上转到C:\Program Files (x86)\Microsoft\Contracts\Languages\CSharp,并在项目中包含ContractExtensions.cs.它包含您需要的一些属性.

What you want is entirely possible, but not many people know it. First, go on your computer to C:\Program Files (x86)\Microsoft\Contracts\Languages\CSharp and include ContractExtensions.cs in your project. It contains some attributes that you need.

然后,应用 ContractAbbreviator 将属性分配给您的方法.您可以删除[Conditional("DEBUG")][ContractVerification(false)]属性,因为可以在项目的代码合同"属性页中为调试和发布"设置合同行为.请注意,您必须在方法开始时调用合同方法,否则将在该位置编写合同.您不能在方法中放入任何其他代码.

Then, apply the ContractAbbreviator attribute to your methods. You can remove the [Conditional("DEBUG")] and [ContractVerification(false)] attributes as you can set the contract behavior for Debug and Release in the Code Contracts property page of your project. Note that you must call your contract methods at the start of the method, where you'd otherwise write the contracts. You cannot put any other code in the methods.

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

While this is an answer to your question, it might not solve your problem. The reason is that the static checker cannot see that when a.CompareTo(b) > 0, a > b holds. So, this example will not work with your generic version, but will work with your non-generic version:

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



显然,我对Assert类完全误解了您的意图.您确实可以按照这个论坛.

Apparently I completely misunderstood your intentions with the Assert class. You can indeed do what was recommended on this forum.

但是,您不能期望静态检查器能够理解,例如,x.CompareTo(y) > 0之后是x > y.原因?您可以在这些方法中直接输入任何内容.例如:

However, you cannot expect the static checker to understand that, for example, from x.CompareTo(y) > 0 follows that x > y. The reason? You can put literally anything in these methods. For example:

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.因此,静态检查器无法看到它们之间的相似性.

You might not even have a CompareTo. So the static checker cannot see the similarities between them.

这篇关于CodeContracts:重用假设/断言?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-22 18:56