为什么Stack.Peek()是一个方法?

9
正如标题所述,为什么Stack类需要一个返回顶部对象引用的方法?我一直被告知,方法意味着涉及某些计算,并且应该使用属性返回简单对象。Peek()方法没有参数,在代码级别上它是(我认为)一个简单的操作。
问题是:是否有具体的原因?是否有任何隐藏的行为会影响性能?
编辑:我不知道类的实现方式,但是如果该方法在下面使用了枚举器,则多次迭代到最后一个元素是不明智的。另一方面,如果它是单个IList,则不应对性能产生任何更大的影响。

栈是一种奇怪的东西,你可以将东西推入和弹出它,但无法获取特定项。有时你想知道顶部的项。因此引入了peek()方法。你也可以使用TopItem等属性。这是一种风格问题,就像@TomTom所说的那样。 - lordkain
1
源代码在这里:http://referencesource-beta.microsoft.com/#mscorlib/system/collections/stack.cs#6acda10c5f8b128e - DaveShaw
@DaveShaw:目前的源码,无论如何。未来版本可能采用不同的实现方法,而不改变接口。 - O. R. Mapper
除了作为答案所说的动词外,它更像是为实际不同的数据保留属性 - peek 是从集合中计算出来的值 - 最后一个项目 - 属性也被展开为方法:例如一个获取器和一个设置器。 - Demetris Leptos
6个回答

12

Peek是一个动词,所以在我的书中,Peek() 应该是一个方法。但是用不同的名称,它也可以是一个属性。

请记住,任何属性都有关联的get和/或set方法,所以无论如何,您最终都会得到一个方法。


我十分确定这个问题不是“为什么代码对象被命名为Peek方法?”,而是“为什么使用方法来查看堆栈顶部的元素?” - decPL
1
然而,用不同的名称表示,它也可以成为一个属性。解决了实现的原因。 - Jonesopolis

6

我理解这个问题是“为什么它是一个方法而不是属性”。

其中一个原因可能是为了保持一致性 - 所有访问方法实际上都是方法。从纯粹的代码角度来看,我认为没有理由不将其作为属性,这完全是一种风格问题。


2

我同意,可以将其作为属性TopItem或类似的内容,因为这样更容易理解,但如果为空,它会抛出异常还是返回null呢?根据MSDN的规定,属性不应该抛出异常。

Stack的源代码参考中,您会看到涉及到抛出特定异常的代码。

    // Returns the top object on the stack without removing it.  If the stack
    // is empty, Peek throws an InvalidOperationException.
    public virtual Object Peek() {
        if (_size==0)
            throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_EmptyStack"));
        Contract.EndContractBlock();
        return _array[_size-1];
    }

现在这与上述属性概念的处理方式不同。所以一个与另一个不同。

编辑-添加了属性文档。虽然不是获胜答案,但提供了更多关于为什么它不是属性的逻辑解释。


1
是的,但“属性”能够像所提到的方法一样精确地起作用。 - Tarec
“我同意,可以将其作为TopItem属性或其他内容,但如果为空,它会抛出异常还是返回null呢?” - 当然会。 - O. R. Mapper
@O.R.Mapper 是非题中的“Yes”不是一个有效的答案。我期望属性不会抛出异常,而是返回null。长期以来Stack功能是个例外。 - bland
@bland:是的,就像“是的,它可以做其中任何一个。” - O. R. Mapper
1
@O.R.Mapper MSDN指出,属性应避免抛出异常。我的观点是,作为一个属性,它改变了功能的实现方式。当堆栈为空时,两者都可以存在,但会导致不同的处理方式。 - bland
@bland:是的,我知道那个列表;它将属性抛出的异常列为AVOID,但不是DO NOT。有时,这样的异常是合适的,例如在Nullable<T>.Value中,因为它们只是表示程序员正在以不正确的方式使用属性(例如在错误的时间)。 - O. R. Mapper

2

文档没有明确说明用哪个集合来处理栈,但基本上没有其他更有效的方法可以让您只访问该集合的“顶部”。我们也不知道“顶部”是第一个还是最后一个元素,可能栈会跟踪哪个元素是“顶部”,并且不会实际删除弹出的成员(至少不是每次弹出它们),以避免必须移动每个其他元素(再次假设它们正在使用类似数组而不是链表的结构)。


1
不确定这是否相关。如果Peek()方法能够获取“顶部”元素,则属性也可以使用完全相同的代码来执行此操作。 - decPL

2

我认为,由于值不是 Stack 本身的属性,而是评估栈当前内容的结果,所以在我看来,方法比属性更合适。

正如C. Evenhuis在他的答案中提到的那样,Peek 是一个动词,因此使用方法更加符合逻辑。由于peek是对栈执行此操作的常用术语,因此使用peek比使用新/不同术语使用属性更有意义。


-1

1
我知道什么是封装。我问的是为什么它被实现为方法而不是只读属性。 - Tarec
1
一个getter方法会暴露内部实现细节 - peek方法仅提供高级功能,而不暴露任何内部数据结构。 - light_303
1
@light_303,您能详细说明一下吗?我不太明白您所说的“揭示内部实现细节”的意思。 - Tarec
1
该回答是不正确的。一个属性并不暴露任何被方法隐藏的实现细节(仅因为一个属性本质上包含一个或两个(get和set)方法)。 - O. R. Mapper
1
编辑后,答案仍然与问题无关。方法和属性都是封装的方式。 - O. R. Mapper
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接