为什么C#限制一套可以声明为const类型? [英] Why does C# limit the set of types that can be declared as const?

查看:113
本文介绍了为什么C#限制一套可以声明为const类型?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

编译器错误 CS0283 表明,只有基本的POD类型(如还有字符串,枚举和空引用)可以声明为常量。有没有人有这种限制的理由理论?举例来说,这将是很好能够申报其他类型,如IntPtr的常量的值。

Compiler error CS0283 indicates that only the basic POD types (as well as strings, enums, and null references) can be declared as const. Does anyone have a theory on the rationale for this limitation? For instance, it would be nice to be able to declare const values of other types, such as IntPtr.

我相信常量的概念实际上是在C#语法糖,而它只是取代了名的任何用途的面值。例如,给定下面的声明,到富的任何引用将与富在编译时更换。

I believe that the concept of const is actually syntactic sugar in C#, and that it just replaces any uses of the name with the literal value. For instance, given the following declaration, any reference to Foo would be replaced with "foo" at compile time.

const string Foo = "foo";

这将排除任何可变类型,所以也许他们选择了这个限制,而不是确定在编译时给定的类型是否是可变的?

This would rule out any mutable types, so maybe they chose this limitation rather than having to determine at compile time whether a given type is mutable?

推荐答案

从的 C#规范,章10.4 - 常量:在结果
(10.4在C#3.0规范,10.3网络版2.0)

一个不变的是重新$ P $类成员psents一个恒定值:可以在编译时计算的值

A constant is a class member that represents a constant value: a value that can be computed at compile time.

这基本上说,你只能使用前pressions是仅由文字。任何方法,构造函数的调用(即不能重新psented纯IL面值$ P $)不能使用,因为没有办法让编译器做执行,这样计算的结果,在编译时。另外,由于没有办法来标记的方法如不变(即有输入和输出之间的一对一的映射),编译器来做到这一点。将任一分析的IL以查看是否唯一的方式这取决于以外的输入参数,特殊情况下处理一些类型(如IntPtr的),或者只是不允许在每次调用任何code的东西。

This basically says that you can only use expressions that consists solely of literals. Any calls to any methods, constructors (that cannot be represented as pure IL literals) cannot be used, as there is no way for the compiler to do that execution, and thus compute the results, at compile time. Also, since there is no way to tag a method as invariant (ie. there is a one-to-one mapping between input and output), the only way for the compiler to do this would be to either analyze the IL to see if it depends on things other than the input parameters, special-case handle some types (like IntPtr), or just disallow every call to any code.

IntPtr的,作为一个例子,虽然是一个值类型,仍然是一个结构,而不是内置的文字中的一个。因此,使用一个IntPtr任何Ex pression需要调用code在IntPtr的结构,这是不合法的常量声明。

IntPtr, as an example, though being a value type, is still a structure, and not one of the built-in literals. As such, any expression using an IntPtr will need to call code in the IntPtr structure, and this is what is not legal for a constant declaration.

唯一合法的恒定值类型的例子,我能想到的将是一个由刚刚宣布它用零初始化,而这几乎是有用的。

The only legal constant value type example I can think of would be one that is initialized with zeroes by just declaring it, and that's hardly useful.

至于如何编译器将/使用常量,它会使用计算值不是恒定的名字在code。

As for how the compiler treats/uses constants, it will use the computed value in place of the constant name in the code.

因此​​,您有以下作用:

Thus, you have the following effect:


  • 没有参照原恒姓名,班级有人宣布,或命名空间,被编译到code在此位置<​​/ li>
  • 如果你反编译code,就会产生神奇的数字在里面,只是因为原来的引用,以不变的是,如上所述,不是present,只有不断的<值/ LI>
  • 编译器可以用它来优化,甚至删除不必要的code。例如,如果(SomeClass.Version == 1),当SomeClass.Version具有1的值,实际上将除去if语句,并保持的块正在执行code。如果该常数的值不是1,则整个if语句和其块将被删除。

  • 由于常数的值被编译成code和不为恒定的基准,使用来自其他组件的常量不会自动地更新以任何方式编译code。如果常数的值应该改变(它不应该!)

  • No reference to the original constant name, class it was declared in, or namespace, is compiled into the code in this location
  • If you decompile the code, it will have magic numbers in it, simply because the original "reference" to the constant is, as mentioned above, not present, only the value of the constant
  • The compiler can use this to optimize, or even remove, unnecessary code. For instance, if (SomeClass.Version == 1), when SomeClass.Version has the value of 1, will in fact remove the if-statement, and keep the block of code being executed. If the value of the constant is not 1, then the whole if-statement and its block will be removed.
  • Since the value of a constant is compiled into the code, and not a reference to the constant, using constants from other assemblies will not automagically update the compiled code in any way if the value of the constant should change (which it should not!)

在换言之,与以下情形:

In other words, with the following scenario:


  1. 大会A,包含一个名为版本不断,具有1
  2. 的值
  3. 大会B,包含一个前pression从该常数分析组件A的版本号,并将其与1,以确保它可以与装配
  4. 工作
  5. 有人修改装配A,常量的值增大为2,重建A(但不是B)

在这种情况下,组件B,在它的编译形式,仍会1的值相比较,以1,因为当B被编译,恒定的值是1

In this case, assembly B, in its compiled form, will still compare the value of 1 to 1, because when B was compiled, the constant had the value 1.

事实上,如果是这样的程序集B在汇编任何一个唯一的使用,程序集B将不执行包含在程序集B的前pression的code对组件A的依赖将编译不加载组件中的。

In fact, if that is the only usage of anything from assembly A in assembly B, assembly B will be compiled without a dependency on assembly A. Executing the code containing that expression in assembly B will not load assembly A.

常量因此应该只用于事情,永远不会改变。如果它是可能或将要改变一些在未来的时间,你不能保证所有其他组件同时重建的值,只读字段是不是常数更合适。

Constants should thus only be used for things that will never change. If it is a value that might or will change some time in the future, and you cannot guarantee that all other assemblies are rebuilt simultaneously, a readonly field is more appropriate than a constant.

因此​​,这是确定的:

So this is ok:


  • 公共常量的Int32 NumberOfDaysInAWeekInGregorianCalendar = 7;

  • 公共常量的Int32 NumberOfHoursInADayOnEarth = 24;

虽然这不是:


  • 公共常量的Int32 AgeOfProgrammer = 25;

  • 公共常量字符串NameOfLastProgrammerThatModifiedAssembly =乔程序员;

修改2016年5月27日

OK,只是得到了一个给予好评,所以我在这里重新阅读我的答案,这实际上是稍有不当。

OK, just got an upvote, so I re-read my answer here and this is actually slightly wrong.

现在,在有意的C#语言规范是一切,我上面写的。你不应该使用的东西,不能与文字psented为常量重新$ P $

Now, the intention of the C# language specification is everything I wrote above. You're not supposed to use something that cannot be represented with a literal as a const.

不过,可以吗?嗯,是的......

But can you? Well, yes....

让我们来看看的 decimal类型。

Let's take a look at the decimal type.

public class Test
{
    public const decimal Value = 10.123M;
}

让我们来看看这是什么类的样子的真正的时候在用ILDASM看:

Let's look at what this class looks like really when looked at with ildasm:

.field public static initonly valuetype [mscorlib]System.Decimal X
.custom instance void [mscorlib]System.Runtime.CompilerServices.DecimalConstantAttribute::.ctor(int8, uint8, uint32, uint32, uint32) = ( 01 00 01 00 00 00 00 00 00 00 00 00 64 00 00 00 00 00 ) 

让我分解为您:

.field public static initonly

对应:

public static readonly

这是正确的,一个常量十进制实际上是一个只读小数

在这里真正的交易是编译器将使用 DecimalConstantAttribute 工作它的魔力。

The real deal here is that the compiler will use that DecimalConstantAttribute to work its magic.

现在,这是唯一的法宝等我所知道的与C#编译器,但我认为这是值得一提。

Now, this is the only such magic I know of with the C# compiler but I thought it was worth mentioning.

这篇关于为什么C#限制一套可以声明为const类型?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆