如何在C#中实现具有前/后条件和不变量的Stack类?

时间:2011-10-05 21:54:49

标签: c# stack invariants contracts

有没有人有关于如何/什么是在C#中实现Stack类的最佳方式的示例或想法?我知道已经有一个Stack类,但我需要了解如何实际实现Stack类。

我还需要有关如何在C#中使用Contracts来指定此类的前置条件,后置条件和不变量的建议。我认为在ASP.NET MVC架构中创建模型之前我曾经使用过类似的东西,但我不完全确定它是否是同一个东西并且工作方式相同。 (我在前置条件/​​后置条件/不变量上有点迷失,如果你还不能说 - 那么请耐心等待。)

我的主要问题 - 有人可以就正确使用合同(如Stack)等方式向我提供建议。

是的,我已经付出了努力:

public interface IStack
{
        void Push(Object e);
        Object Pop();
        Object Top();
        void EnsureCapacity();
    }
}

   public class Stack : IStack
{
    private Object[] elements;
    private int size = 0;

    public Stack()
    {
        elements = new Object[0];
    }

    public void Push(Object e)
    {
        // check if this array capacity has been reached and increase if needed
        EnsureCapacity();
        elements[size++] = e;
    }

    public Object Pop()
    {
        // check if the method call is invalid for the object's current state
        if (size == 0) throw new InvalidOperationException("Stack.Pop");

        Object result = elements[--size];
        elements[size] = null;

        return result;
    }

    public Object Top()
    {
        // check if the method call is invalid for the object's current state
        if (size == 0) throw new InvalidOperationException("Stack.top");
        return elements[(size - 1)];
    }

    private void EnsureCapacity()
    {
        if (elements.Length == size)
        {
            Object[] oldElements = elements;
            elements = new Object[(2 * size + 1)];
        }
    }
}

3 个答案:

答案 0 :(得分:1)

c#中实现的许多集合都基于数组。您可以使用数组并添加元素到最后,保留顶级elemnet的索引并在推送新元素时增加它,当然当新对象出现时,数组将“必须被扩展”(由新的替换)并且有在当前数组中没有它们的位置。

代码合同在http://research.microsoft.com/en-us/projects/contracts/userdoc.pdf

上提供了非常好的文档

答案 1 :(得分:1)

如果您愿意,为了开始使用Microsoft Code Contracts,我曾对blog post做过一次。该职位涵盖了基本的前提条件,后置条件和不变量。

作为概念的摘要,您可以将它们想象如下:

  • 在执行方法之前必须满足的前提条件 - 客户承诺您的方法。
  • 就您班级的客户而言,不变性必须始终保持公开真实。
  • 后置条件是方法执行后必须遵循的 - 您的方法向客户承诺的内容。

所以,在我的头顶,对于一个堆栈,一个容易想到的事情可能是一个不变的。如果您使用数组对堆栈建模,则可以在类中声明一个永远不会设置为null的类的不变量,例如,您将定义不变方法:

[ContractInvariantMethod]
private void ObjectInvariant()
{
   Contract.Invariant(elements != null);
}   

看起来你已经有了一个pop方法的先决条件 - 你想说用户有责任在执行pop时确保堆栈不为空。所以,在pop方法的开头,你有:

Contract.Requires(size > 0);

最后,你可能会在pop上指定一个后置条件,该大小将始终小于pop操作之前的大小(如果你愿意,可以更具体):

Contract.Ensures(Contract.OldValue<int>(size) > size);
祝你好运 - 合同很酷且很有用。这是一种非常干净的编码方式。

答案 2 :(得分:0)

由@wiero链接的文件很好。如果您想了解CodeContracts实现支持的概念背后的使用和推理,请查找“按合同设计”的信息,其中的介绍如下:

http://en.wikipedia.org/wiki/Design_by_contract

Bertrand Meyer在他的“面向对象的软件构建”一书中对它的概念很受欢迎,并对其进行了深入的讨论。由于他通过他的公司将“Design By Contract”这个名称注册为商标,因此其他实现必须具有不同的名称(例如“CodeContracts”)。