var s = "abcd";
但是为什么当变量是一个常量时,类型不能被推断出来呢?
以下代码会抛出编译时异常:
const var s = "abcd"; // <= Compile time error:
// Implicitly-typed local variables cannot be constant
var s = "abcd";
但是为什么当变量是一个常量时,类型不能被推断出来呢?
以下代码会抛出编译时异常:
const var s = "abcd"; // <= Compile time error:
// Implicitly-typed local variables cannot be constant
我真的希望Lippert过来看一下这个问题
如果有什么想让我注意的事情,你可以在文本中留下我的名字(不是评论),我最终会找到它。或者更好的方法是,你可以“发送推特”给@ericlippert
。请注意,这并不构成服务级别协议;我会在空闲时间处理。
为什么当变量是常量时不能推断类型?
“常量”和“变量”是相反的概念。const var
让我毛骨悚然。常量是一个永远不会改变且没有存储位置的值;变量是一个存储位置,其内容会发生变化。它们完全不同,因此不要尝试将它们结合起来。选择var
语法是为了强调“这是一个变量”,我们将坚持使用它。
var
可以代替具体类型声明,但与const
结合使用会严重混淆编译器对值的处理方式。因此,禁止使用const var
以避免混淆,你必须显式地为常量指定类型。
如果有不使用var
的推断常量,我会非常满意:
const Pi = 3.14159;
对我来说看起来没问题。然而,我不知道是否有将其添加到C#的计划。
var
关键字作为已知类型的语法糖(例如 var s = "abc";
)? - Andreas Grech我同意Eric的观点,这实在是丑陋得令人发指:
const var s = "abcd"
但为什么不直接这样呢?
const s = "abcd"
对我来说,这似乎是一种合理的语法。
//Assembly A, Class Widget defines this:
public static const System.Decimal Pi = 3.14
那么您就有一个 A 的消费者:
//somewhere in the Program.exe assembly
decimal myCircleCurcum = 2 * Widget.pi
程序.exe的编译后中间语言(IL)大致会执行以下伪代码:
// pseudo-IL just to illustrate what would happen to the const
myCircleCurcum = 2*3.14
注意,消费程序集并不知道十进制数3.14与程序集A有任何关系 - 对于program.exe来说,它只是一个文字值。对我来说,这是C#编译器的一种合理行为 - 毕竟,程序集A明确声明pi是一个常量(这意味着该值始终为pi=3.14)。但我敢说,99%的C#开发人员都不了解这个问题的影响,并可能随意将π更改为3.1415。
常量在跨程序集版本方面存在很大问题(这也来自Richter),因为使用包含常量的程序集的消费者不会看到程序集中的常量更改(即重新编译)。这可能会导致消费程序集A的人非常难以找出的错误......以至于我禁止我的团队使用常量。它们稍微提升的性能并不值得它们可能引起的微妙错误。
你只能在确定该值永远都不会更改时才能使用常量 - 即使像π这样被设置为const,你也不能肯定你将来不想要改变精度。
如果程序集A定义:
decimal const pi = 3.14
那么你构建它,然后其他程序集使用它,如果你之后更改了程序集A:
decimal const pi = 3.1415
即使重新构建程序集A,程序集A的消费者仍然会保留旧值3.14!为什么?因为最初的3.14被定义为常量,这意味着程序集A的消费者已经被告知该值不会改变--因此他们可以将pi的值嵌入自己的元数据中(如果重新构建程序集A的消费者,它将得到新的pi值)。再次强调,我认为这并不是C#编译器处理常量的问题--只是开发人员可能不希望在某些情况下无法安全地更改常量的值,在其他情况下则可以安全地更改。安全:消费者永远不会仅通过.dll进行引用(即他们每次都会从源代码构建),不安全:消费者不知道您定义在程序集中的const何时会发生更改。 .NET文档中应该明确指出常量意味着无法在源代码中更改其值。int
乘以int
常量与将int
乘以一个值可以适合int
的long
常量非常不同。 - supercatconst
就像一个替代品,而不是像 JavaScript 或者 C 一样可以在运行时初始化动态值的东西。所以,除了 using
和 foreach
变量之外,C# 并没有提供一种标记本地变量为不可变的方法。 - binkivar s = "abc";
时阻止我呢? - Andreas Grech如果你认为艾瑞克的论点完全是基于不必要的复杂语义解释,那么就试着围绕“变量”这个意思来构建同样的论点,假设它被称为另一个名字,比如impl。难道impl不能与const一起使用吗?我很难想出任何一个理由。因此,问题归结为不喜欢“const var”听起来的方式而已,别无他意。我认为我们大多数人都可以轻松克服这个问题。
虽然我不同意Lippert先生的推理,但是有一个很好的理由不允许命名常量的隐式类型转换:考虑以下代码的含义,如果类型化的常量不必明确指定它们的类型:
const var ScaleFactor = 2500000000; // Type 'Int64'
...
int thisValue = getNextInt();
total += thisValue * ScaleFactor;
现在假设比例因子需要降低20%。将值更改为2000000000会产生什么影响?即使在代码中指定了该值[例如,当将total += thisValue * 2500000000;
更改为 total += thisValue * 2000000000;
时],出现Int64变为Int32的问题仍然会发生,因为更改会相邻于要求该值为 Int64
的代码。相比之下, const
声明可能远离其作用的代码,因此没有可见的方法来知道某个代码是否依赖长类型的常量。
long
是 0L
,带有 .
的任何内容默认为 double
,float
是 0F
,decimal
是 0M
,没有 .
的任何内容都是 int
)。当然,说 const s = 25000L
并不比 const long s = 25000
更容易,而且你仍然需要指定类型。 - drzausfloat
和double
转换的规则是相反的。如果合法,语句float foo = 0.1;
将完全产生预期的效果,但是const float ten=10.0f; double wrong = 1 / ten;
不会,即使ten
保存了精确的float
值。让我感到恼火的是错误的那个甚至没有产生警告,但正确的那个却无法编译。 - supercat我不同意 @Eric 的观点。
var 关键字并不意味着“这是一个变量”,而是意味着“类型将被推断”。
int、long 等是否是用于标识变量的“关键字”?不,它们只是数据类型,可以用于变量或常量。
我认为 var 关键字的名称被认为类似于 Javascript,我认为这是不合适的。
auto 呢?(http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2004/n1705.pdf)
var
不是它的创建者在编写时所想的意思,这需要勇气...也许你的意思是 不应该 :) - nawfalconst
关键字的行为。也就是说,在运行时计算它的能力,但在后续代码中禁止更新它。当您只想计算一次值时,这很有用,因为它可以强制执行纪律并明确。readonly
关键字。也就是说,这种语法可能很有用:// This variable should never be overwritten!
readonly var target = 4;
在C#中,这并不是没有先例。 using()
和迭代(foreach
)变量已经表现出了这种方式:
class Program
{
static void Main(string[] args)
{
foreach (var x in new[] { "asdf", })
{
System.Console.WriteLine(x);
// error CS1656: Cannot assign to 'x' because it is a 'foreach iteration variable'
x = "food";
}
}
}
哦,看到了我得到了类型推断和只读行为!太棒了!然而,在实际代码中使用foreach
关键字会让人感觉非常笨拙。你试图保护自己或同事不经思考就添加修改x
的代码,很难显露出来(除非在编译时发现错误)。这就是为什么如果它成为一种语言特性将会很棒。
http://msdn.microsoft.com/en-us/library/bb310881.aspx
编译器错误 CS0822var s = "abc";
,类型也是已知的,但是没有编译器错误,因为类型是推断出来的。所以你的答案并没有真正回答我的问题。 - Andreas Grech有趣。我不知道这是C#编译器的限制还是语言本身的基本限制。
为了解释我的意思,请考虑VB。
在VB 9中,您也无法推断常量,但这只是编译器的限制。 在VB 10中,他们能够添加常量类型推断,而不对语言进行任何重大更改。
var
关键字的主要目的是允许使用匿名类型;这是唯一一种你真正需要var
关键字的情况。 - Fredrik Mörk