上周末,当我遇到an open source project来查找a bit of code that confused me中的使用情况时,我正在C# specification上插件。
问题中的代码如下:
internal static class SomeStaticClass
{
private const int CommonlyUsedValue = 42;
internal static string UseCommonlyUsedValue(...)
{
// some code
value = CommonlyUsedValue + ...;
return value.ToString();
}
}
我被猝不及防,因为这似乎是静态函数使用的非静态字段,有些如何在静态类中编译得很好!
规范声明(§10.4):
常数声明可能包括a 一组属性(§17),一个新的 修饰符(§10.3.4),并且是有效的 四种访问的组合 修饰语(§10.3.5)。属性 和修饰符适用于所有 成员宣布成员 常数声明。 尽管如此 常量被认为是静态的 成员,不断声明 既不需要也不允许静态 修饰符。这是一个错误 修饰符在a中出现多次 不断声明。
所以现在它更有意义,因为常量被认为是静态成员,但句子的其余部分对我来说有点令人惊讶。为什么一个常量声明既不需要也不允许静态修饰符?不可否认,我不知道这个规格是否足以让它立即变得有意义,但为什么决定不强制常量使用静态修饰符,如果它们被认为是静态的?
查看该段落中的最后一句,我无法弄清楚它是否直接与前一个语句有关,并且在常量上有一些隐式静态修饰符,或者它是否独立于常量的另一个规则。任何人都可以帮我解决这个问题吗?
答案 0 :(得分:60)
更新:This question was the subject of my blog on June 10th, 2010.感谢您提出质疑!
为什么决定不强制常量使用静态修饰符(如果它们被认为是静态的?)
假设常量被认为是静态的。有三种可能的选择:
使静态可选:“const int x ...”或“static const int x ...”都是合法的。
使静态必需:“const int x ...”是非法的,“static const int x ...”是合法的
使静态非法:“const int x ...”合法,“static const int x ...”是非法的。
您的问题是我们为什么选择(3)?
1999年的设计说明没有说;我刚刚检查过但是我们可以推断出语言设计师的头脑可能会发生什么。
(1)的问题是你可以阅读同时使用“const int x ...”和“static const int y ...”的代码然后你自然会问自己“有什么区别?”由于非常量字段和方法的默认值是“实例”,除非是“静态”,因此自然的结论是某些常量是每个实例,而某些常量是每个类型,并且这个结论是错误的。这很糟糕,因为它具有误导性。
(2)的问题是,首先,它是多余的。这只是更多的打字而没有增加语言的清晰度或表现力。第二,我不了解你,但我个人讨厌它,当编译器给我错误“你忘了在这里说出这个神奇的词。我知道你忘了说出这个神奇的词,我百分之百能干弄明白这个神奇的词需要去那里,但是除非你说出神奇的词,否则我不会让你完成任何工作。
(3)的问题是开发人员需要知道const逻辑意味着静态。然而,一旦开发人员了解到这一事实,他们就已经学会了这一点。这不是一个很难弄清楚的复杂想法。
为最终用户提供最少问题和成本的解决方案是(3)。
将这与其他地方进行比较和对比很有意思,因为语言中做出了不同的决定。
例如,重载运算符必须是公共的和静态的。在这种情况下,我们再次面临三个选择:
使公共静态可选,
使其成为必需品,或
将其视为非法。
对于重载运算符,我们选择了(2)。由于方法的自然状态是私有/实例,所以看起来像公共/静态的方法看起来很隐蔽和误导,因为(1)和(3)都需要。
对于另一个示例,与基类中的虚方法具有相同签名的虚方法应该在其上具有“新”或“覆盖”。再次,三个选择。
使其成为可选:您可以说新的,或覆盖,或者根本不说,在这种情况下我们默认为new。
使其成为必需:您必须说新的或覆盖,或
使其成为非法:你根本不能说新的,所以如果你不说覆盖,那么它会自动成为新的。
在这种情况下,我们选择(1)因为这对于脆弱的基类情况最有效,某人将虚拟方法添加到您没有意识到您现在重写的基类。这会产生警告,但不会产生错误。
我的观点是,必须根据具体情况考虑每种情况。这里没有太多的一般指导。
答案 1 :(得分:43)
基本上, const 已经暗示 static ,因为在运行时无法更改该值。您没有理由声明 static const ,因为它已经隐含了,语言设计者决定使语言语法反映出来。
规范语言基本上是说“Const总是静态的,所以你不能明确地说静态和const,因为它是多余的。”
答案 2 :(得分:9)
这不是必需的或允许的,因为它是多余的。如果所有const
成员都是静态的,那么只允许将的某些指定为static
并且其中一些
答案 3 :(得分:0)
禁止将声明常量声明为静态的另一个原因是,从CLR的角度来看,常量不会与该类型的其他静态字段一起存储在内存中。
常量没有内存地址,你不能引用常量值(唯一的例外是字符串常量)。在运行时,如果未引用其他静态/非静态成员,则不会加载类型保持常量定义。如果它是程序集中唯一的类型,您甚至可以在编译后安全地从磁盘中删除它的DLL。
因此,常量只是'可以从静态方法引用'的'静态'。常量没有其他静态类型成员那样的“静态”属性。