编译时常量不一致

12

更新:这似乎是编译器的误导,因为以下代码实际上是有效的:

const int MyInt = default(int);
问题在于DateTime不是一个有效的const,而不是default的使用。让我感到困惑的主要原因是没有意识到在可选参数中特别处理了default(DateTime)(我得出了一个错误的结论,即由于错误消息省略了其他可能的条件,default(DateTime)被视为编译时常量)。MarcinJuraszek在他的答案中解决了这个问题。
原始问题:

这是从Marc Gravell的评论中无耻地撕下来的这个答案另一个问题。

为什么以下代码是有效的:

// No compiler errors, default(DateTime) seems to satisfy the compile-time constant requirement.
public static void DoSomething(DateTime date = default(DateTime))
{ 
}

但以下内容不行:

// Compiler error: "Constant initializer must be compile-time constant.
const DateTime MyDate = default(DateTime); 

由于两者都需要“编译时常量”(如果您尝试为可选参数提供像DateTime.MinValue这样的内容,编译器会报错,因为它不是编译时常量),因此可以看出:

// Compiler error: Default parameter value for 'date' must be a compile-time constant.
public static void DoSomething(DateTime date = DateTime.MinValue) {}

编译器在幕后进行了什么处理,导致它们被区别对待?


可选参数是事后添加的。 - Daniel A. White
看编译器的信息,它可能会告诉你一些东西。 - usr
@DanielA.White - 如果我没记错,default是在引入泛型时才添加的。 - Damien_The_Unbeliever
@usr 嗯,编译器消息是混乱的根源伙计。 - Adam Houldsworth
看起来这是规范的一部分。我真的应该在某个时候更仔细地阅读它! - Simon Whitehead
@usr 根据您的评论,构建错误消息指出 DateTime 不是有效的常量,但 IDE 中的错误消息跳到了 default 问题,这是一个误导。 - Adam Houldsworth
3个回答

7
这在C#规范(10.6.1)中有描述:
一个带有默认参数的固定参数被称为可选参数,而没有默认参数的固定参数是必需的参数。必需参数不能出现在形式参数列表中的可选参数后面。
ref或out参数不能有默认参数。默认参数中的表达式必须是以下之一:
常量表达式
形如new S()的表达式,其中S是值类型
形如default(S)的表达式,其中S是值类型
但你说得对,要求编译时常量的错误消息并不好。

你还应该说默认值是在运行时评估的操作符,那么这个答案就完美了。 - BlackBear
@Marcin C#规范(5.0)的7.19节:“常量表达式”...“常量表达式是指可以在编译时完全计算出来的表达式。”...“只有以下结构允许在常量表达式中使用:”...“• 默认值表达式”。 - xanatos

4

default()在运行时计算。 DateTime.MinValue未声明为const。

只有声明为const的符号才能用于成员初始化和属性声明。

可选参数是一种特殊情况。编译器会为您生成重载。从语义上讲,它想要一个const,但从技术上讲,默认值也可以作为编译器知道如何在生成的重载中使用它。

MSDN指出,可选参数通过设计接受default()new() http://msdn.microsoft.com/en-us/library/dd264739.aspx

关于const定义;

常量表达式是可以在编译时完全评估的表达式。

我同意这种区别很微小,而且它已经绊倒了我不止一次。


2
我认为这并没有回答问题。我知道 DateTime.MinValue 不是常量,但在某种情况下,default(DateTime) 是常量,而在另一种情况下则“不是”。 - Adam Houldsworth
1
C#规范(5.0)的7.19节:“常量表达式”...“常量表达式是指可以在编译时完全计算出来的表达式。”...“只有以下结构允许在常量表达式中使用:”...“• 默认值表达式”。 - xanatos

4
因为仅可以具有值 "default(TypeOfCost)" 的“const”可能非常无用 :-)... 而且您甚至不能稍后更改它 :-)
请注意,“default(TypeOfConst)”是常量表达式。
从C#规范(5.0)中得知:7.19常量表达式... 常量表达式是一个可以在编译时完全评估的表达式。... 只允许在常量表达式中使用以下结构:... • 默认值表达式 错误在于“const DateTime”是非法的。 10.4常量... 常量声明中指定的类型必须是sbyte、byte、short、ushort、int、uint、long、ulong、char、float、double、decimal、bool、string、枚举类型或引用类型之一。

PI只能取值3.14...,但我仍然认为它很有用。 - SWeko
@AdamHouldsworth 我得到的错误是 无法声明类型“System.DateTime”为const - xanatos
@AdamHouldsworth 一个更有趣的例子是,你不能将 default(DateTime) 用作属性参数 :-) - xanatos
@SWeko PI是double类型的2^64个值之一,很难计算。default(ReferenceType) == null,default(ValueType) ==“零化的ValueType”。它们是相当简单的结果。 - xanatos
@xanatos 这里的 "default value expressions" 是指 default(type) 这种默认值表达式,还是像 int i = 1; 这样的字面量默认值呢? - Adam Houldsworth
显示剩余5条评论

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