And*_*ech 40 c# type-inference constants
在C#中,以下类型推断有效:
var s = "abcd";
Run Code Online (Sandbox Code Playgroud)
但是,当变量是常数时,为什么不能推断出类型呢?
以下引发了编译时异常:
const var s = "abcd"; // <= Compile time error:
// Implicitly-typed local variables cannot be constant
Run Code Online (Sandbox Code Playgroud)
Eri*_*ert 33
我实际上希望Lippert流行,然后看看这个问题
如果您想引起我的注意,您可以在文本中留下我的名字 - 而不是评论 - 我最终会找到它.或者,更好的是,你可以"推特"到@ericlippert.请注意,这不构成服务级别协议; 我在业余时间这样做.
当变量是常量时,为什么不能推断出类型呢?
"常数"和"变量"是对立的. const var给我打电话的颤抖.常量是一个永远不会改变且没有存储位置的值; 变量是其内容发生变化的存储位置.它们完全不同,所以不要试图将它们结合起来.该var语法被选为喊一声"这是一个变量",我们正在与它坚持.
var可以站在一个特定类型声明,但它与合并const严重muddies的编译器什么的图片确实与价值.因此const var不允许这种混淆,你必须明确键入你的常量.
对于不使用的推断常量,我会完全没问题var:
const Pi = 3.14159;
Run Code Online (Sandbox Code Playgroud)
对我来说似乎很好.但是,我知道没有计划将其添加到C#中.
Kev*_*Won 12
这只是一个猜测,但我认为原因可能与const值在编译时放入元数据(它具有所有它自己的微妙后果)这一事实有关.我想知道编译器是否有一些问题可以找出如何将var转换为元数据.
在Richter的CLR VIA C#中(第177页),
定义常量会导致元数据的创建.当代码引用常量符号时,编译器在定义该常量的程序集的元数据中查找该符号,提取常量的值,并将值嵌入到发出的IL代码中.
他接着指出,这意味着由于这个原因你无法获得对常量的记忆的引用.为了使它更加明确,在psuedo C#中,如果程序集A定义了一个const:
//Assembly A, Class Widget defines this:
public static const System.Decimal Pi = 3.14
Run Code Online (Sandbox Code Playgroud)
然后你有A的消费者:
//somewhere in the Program.exe assembly
decimal myCircleCurcum = 2 * Widget.pi
Run Code Online (Sandbox Code Playgroud)
由此得到的program.exe编译后的IL会做类似这样的伪代码:
// pseudo-IL just to illustrate what would happen to the const
myCircleCurcum = 2*3.14
Run Code Online (Sandbox Code Playgroud)
请注意,消费组件根本不知道小数3.14与程序集A有任何关系 - 它是program.exe的一个文字值.对我来说,这是C#编译器行为的合理方式 - 毕竟,程序集A 明确声明pi是一个常量(意味着值是一次且对于所有pi = 3.14).但是,我冒昧地猜测,99%的C#开发人员不理解这种情况的后果,可能会随心所欲地将pi改为3.1415.
常量具有非常差的跨组件版本故事(同样,这来自Richter),因为如果程序集A的常量发生变化(即它被重新编译),具有常量的程序集A的使用者将不会看到更改.这可能导致很难找出组件A的消费者的错误..所以我禁止我的团队使用常量.他们的轻微性能增加不值得他们可能导致的微妙错误.
你真的只能使用一个常数,如果你知道这个值永远不会改变 - 甚至把某些东西设置成一个const就像pi一样,你不能肯定地说你不希望你的percision改变在将来.
如果程序集A定义:
decimal const pi = 3.14
Run Code Online (Sandbox Code Playgroud)
然后你构建它,然后其他程序集使用它,如果你然后更改程序集A:
decimal const pi = 3.1415
Run Code Online (Sandbox Code Playgroud)
并重建程序集A,程序集A的使用者仍将具有旧值3.14!为什么?因为原始3.14被定义为常量,这意味着程序集A的消费者被告知该值不会改变 - 因此他们可以将pi的值烘焙到他们自己的元数据中(如果你重建了程序集A的消费者)然后将在其元数据中获得pi的新值.同样,我不认为这是CSC处理常量的方式的问题 - 只是开发人员可能不希望不能安全地更改常量在某些情况下,可以在其他情况下安全地更改.安全:没有消费者永远只能通过.dll引用(即它们将始终从源构建每个时间),不安全:消费者不知道你的程序集的源代码何时定义它改变了.在.NET文档中可能应该更加清楚,常量意味着您无法更改源代码中的值
出于这个原因,我强烈建议不要使用常量,而只是简单地使小部件.你能真正说出多少值真的永远是永恒的?
在我的脑海中使用const而不是readonly的唯一真正原因是,某些东西可能会对性能产生影响......但如果你遇到这种情况,我会想知道C#是否真的是你问题的正确语言.简而言之,对我而言,使用常量绝不是一个好主意.极少数情况下,微小的性能改善值得潜在的问题.
Kei*_*ght 11
我同意埃里克的观点,认为这是罪恶的丑陋:
const var s = "abcd"
但为什么不简单呢?
const s = "abcd"
对我来说似乎是一个合理的语法.