在静态类中使用常量
上周末我正在埋头苦干一个开源项目,这时我遇到了一些让我困惑的代码在C# 规范中查找用法。
问题中的代码如下:
internal static class SomeStaticClass
{
private const int CommonlyUsedValue = 42;
internal static string UseCommonlyUsedValue(...)
{
// some code
value = CommonlyUsedValue + ...;
return value.ToString();
}
}
我措手不及,因为这似乎是静态函数使用的非静态字段,而静态函数在静态类中编译得很好!
规范规定 (§10.4):
常量声明可以包括 属性集(§17),一个新的 修饰符(§10.3.4),和一个有效的 四种访问方式的组合 修饰符(第 10.3.5 节)。属性 和修饰符适用于所有 宣布的成员 常量声明。 尽管 常量被认为是静态的 成员,常量声明 既不需要也不允许静态 修饰符。对于相同的内容来说这是一个错误 修饰符在一个中多次出现 常量声明。
所以现在它更有意义了,因为常量被视为静态成员,但句子的其余部分对我来说有点令人惊讶。为什么常量声明既不需要也不允许使用 static 修饰符?诚然,我对规范的了解不够充分,无法立即理解这一点,但是为什么决定不强制常量使用 static 修饰符(如果它们被认为是静态的)?
该段的最后一句话,我无法弄清楚它是否直接与前一个语句有关,并且首先对常量有一些隐式静态修饰符,或者它是否独立作为常量的另一个规则。谁能帮我解决这个问题吗?
I was plugging away on an open source project this past weekend when I ran into a bit of code that confused me to look up the usage in the C# specification.
The code in questions is as follows:
internal static class SomeStaticClass
{
private const int CommonlyUsedValue = 42;
internal static string UseCommonlyUsedValue(...)
{
// some code
value = CommonlyUsedValue + ...;
return value.ToString();
}
}
I was caught off guard because this appears to be a non static field being used by a static function which some how compiled just fine in a static class!
The specification states (§10.4):
A constant-declaration may include a
set of attributes (§17), a new
modifier (§10.3.4), and a valid
combination of the four access
modifiers (§10.3.5). The attributes
and modifiers apply to all of the
members declared by the
constant-declaration. Even though
constants are considered static
members, a constant-declaration
neither requires nor allows a static
modifier. It is an error for the same
modifier to appear multiple times in a
constant declaration.
So now it makes a little more sense because constants are considered static members, but the rest of the sentence is a bit surprising to me. Why is it that a constant-declaration neither requires nor allows a static modifier? Admittedly I did not know the spec well enough for this to immediately make sense in the first place, but why was the decision made to not force constants to use the static modifier if they are considered static?
Looking at the last sentence in that paragraph, I cannot figure out if it is regarding the previous statement directly and there is some implicit static modifier on constants to begin with, or if it stands on its own as another rule for constants. Can anyone help me clear this up?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
更新: 这个问题是我的主题2010 年 6 月 10 日发表博客。 感谢您提出这个好问题!
假设常量被认为是静态的。有三种可能的选择:
使静态成为可选:“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)。
将其与语言中做出不同决定的其他地方进行比较和对比是很有趣的。
例如,重载运算符必须是公共的和静态的。在这种情况下,我们再次面临三个选择:
使 public static 可选,
将其设置为必需,或者
使其非法。
对于重载运算符,我们选择 (2)。由于方法的自然状态是私有/实例,因此将看起来像方法公共/静态的东西隐藏起来似乎很奇怪和具有误导性,正如(1)和(3)都需要的那样。
再例如,与基类中的虚拟方法具有相同签名的虚拟方法应该具有“new”或“override”。再次,三个选择。
使其可选:您可以说 new,或 override,或什么都不说,在这种情况下,我们默认为 new。
使其成为必需:您必须说 new 或 override,或者
使其非法:您根本不能说 new,因此如果您不说 override,那么它会自动成为 new。
在本例中,我们选择 (1),因为这最适合脆弱的基类情况,即某人向基类添加了虚拟方法,但您没有意识到您现在正在重写该方法。这会产生警告,但不会产生错误。
我的观点是,每种情况都必须根据具体情况进行考虑。这里没有太多一般指导。
UPDATE: This question was the subject of my blog on June 10th, 2010. Thanks for the great question!
Suppose constants are considered to be static. There are three possible choices:
Make static optional: "const int x..." or "static const int x..." are both legal.
Make static required: "const int x..." is illegal, "static const int x..." is legal
Make static illegal: "const int x..." is legal, "static const int x..." is illegal.
Your question is why did we choose (3)?
The design notes from 1999 do not say; I just checked. But we can deduce what was probably going through the language designer's heads.
The problem with (1) is that you could read code that uses both "const int x..." and "static const int y..." and then you would naturally ask yourself "what's the difference?" Since the default for non-constant fields and methods is "instance" unless "static", the natural conclusion would be that some constants are per-instance and some are per-type, and that conclusion would be wrong. This is bad because it is misleading.
The problem with (2) is that first off, it is redundant. It's just more typing without adding clarity or expressiveness to the language. And second, I don't know about you, but I personally hate it when the compiler gives me the error "You forgot to say the magic word right here. I know you forgot to say the magic word, I am one hundred percent capable of figuring out that the magic word needs to go there, but I'm not going to let you get any work done until you say the magic word".
The problem with (3) is that the developer is required to know that const logically implies static. However, once the developer learns this fact, they've learned it. It's not like this is a complex idea that is hard to figure out.
The solution which presents the fewest problems and costs to the end user is (3).
It is interesting to compare and contrast this with other places in the language where different decisions were made.
For example, overloaded operators are required to be both public and static. In this case, again we are faced with three options:
make public static optional,
make it required, or
make it illegal.
For overloaded operators we chose (2). Since the natural state of a method is private/instance it seems bizarre and misleading to make something that looks like a method public/static invisibly, as (1) and (3) both require.
For another example, a virtual method with the same signature as a virtual method in a base class is supposed to have either "new" or "override" on it. Again, three choices.
make it optional: you can say new, or override, or nothing at all, in which case we default to new.
make it required: you have to say new or override, or
make it illegal: you cannot say new at all, so if you don't say override then it is automatically new.
In this case we chose (1) because that works best for the brittle base class situation of someone adds a virtual method to a base class that you don't realize you are now overriding. This produces a warning, but not an error.
My point is that each of these situations has to be considered on a case-by-case basis. There's not much general guidance here.
基本上,const 已经意味着静态,因为该值无法在运行时更改。您没有理由声明static const,因为它已经隐含了,并且语言设计者决定让语言语法反映这一点。
规范语言基本上是说“Const 总是静态的,所以你不能明确地说 static 和 const,因为它是多余的。”
Basically, const implies static already, since the value cannot be changed at runtime. There's no reason for you to ever declare static const, since it's already implied, and the language designers decided to make the language syntax reflect that.
The specification language is basically saying "Const is always static, so you can't explicitly say static and const since it's redundant."
它不是必需的或允许的,因为它是多余的。如果所有
const
成员都是静态的,那么只有允许其中一些被指定为static
而另一些则不被指定时才会产生混乱。 。It isn't required or allowed because it's redundant. If all
const
members are static, then only confusion can arise from allowing some of them to be specified asstatic
and some of them not to be.禁止将常量声明为静态的另一个原因是,从 CLR 的角度来看,常量不会与该类型的其他静态字段一起存储在内存中。
常量没有内存地址,您无法获取对常量值的引用(唯一的例外是字符串常量)。在运行时,如果未引用其他静态/非静态成员,则不会加载保存常量定义的类型。如果它是程序集中的唯一类型,您甚至可以在编译后安全地从磁盘中删除它的 DLL。
因此,仅就“可以从静态方法引用”而言,常量才是“静态”的。常量不像其他静态类型成员那样具有任何其他“静态”属性。
Another reason to disallow declare constants as static is that from CLR point of view the constants are not not stored in memory along with other static fields of the type.
The constants don't have memory address and you cannot get reference to the constant value (the only exception is string constants). At runtime the type holding constant definition won't be loaded if other static/nonstatic members are not referenced. If it is the only type in the assembly, you can even safely delete it's DLL from the disk after compilation.
So, the constants are 'static' only in terms of 'may be referenced from static methods'. Constants do not have any other 'static' properties as other static type members do.