Type-inferring a constant in C#

后端 未结 11 1130
花落未央
花落未央 2020-12-05 13:14

In C#, the following type-inference works:

var s = \"abcd\";

But why can\'t the type be inferred when the variable is a constant?

T

相关标签:
11条回答
  • 2020-12-05 13:23

    I'm actually hoping Lippert pops by and and takes a look at the question

    If there's something you want brought to my attention, you can leave my name in the text -- not a comment -- and I'll find it eventually. Or, better, you can "tweet" to @ericlippert. Note that this does not constitute a service level agreement; I do this in my spare time.

    why can't the type be inferred when the variable is a constant?

    "constant" and "variable" are opposites. const var gives me the shudders to type. A constant is a value that never changes and has no storage location; a variable is a storage location whose contents change. They're completely different, so don't attempt to combine them. The var syntax was chosen to call out "this is a variable", and we're sticking with it.

    var can stand in for a specific type declaration, but combining it with const severely muddies the picture of what the compiler does with the value. Therefore const var is disallowed to prevent this confusion and you have to explicitly type your constants.

    I would be perfectly fine with inferred constants that do not use var:

    const Pi = 3.14159;
    

    seems fine to me. However, I know of no plans to add this to C#.

    0 讨论(0)
  • 2020-12-05 13:23

    I don't agree with @Eric.

    The var keyword doesn't mean "this is a variable", it means "the type is to be inferred".

    Did int, long, etc. are "keywords" to identify variables? No, they are just data types, can be used for variables or constants.

    I think the name of the keyword var was thought to resemble Javascript and I consider inappropriate.

    How about auto ? ( http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2004/n1705.pdf )

    0 讨论(0)
  • 2020-12-05 13:27

    While I disagree with Mr. Lippert's reasoning, there is a good reason not to allow implicit typing of named constants: consider the meaning of the following code, if typed constants did not have to specify their type explicitly:

    const var ScaleFactor = 2500000000; // Type 'Int64'
    
    ...
    int thisValue = getNextInt();
    total += thisValue * ScaleFactor;
    

    Now suppose that the scale factor needs to be notched down by 20%. What would be the effect of changing the value to 2000000000? While the problem of having an Int64 become an Int32 would occur even if the value were specifed in the code [e.g. when changing total += thisValue * 2500000000; to total += thisValue * 2000000000; the change would be adjacent to the code that requires that the value be an Int64. By contrast, a const declaration would likely be far removed from the code it effects, so there would be no visible way of knowing whether code somewhere might rely upon a constant being a long type.

    0 讨论(0)
  • 2020-12-05 13:27

    IMO var main purpose is to allow anonymous types (type is unknown, with var you can declare a variable to store it). The more common usage now is to write less code ;). As they explain here if you know the type and the value (which won't change) just write the type.

    0 讨论(0)
  • 2020-12-05 13:29

    This is just a guess, but I think that the reason might have to do with the fact that const values are put in metadata (which has subtle consequences all it's own) when compiled. I wonder if maybe the compiler has some issues figuring out how to transform a var to metadata.

    In Richter's CLR VIA C# (page 177),

    Defining a constant causes creation of metadata. When code refers to a constant symbol, compilers look up that symbol in the metadata of the assembly that defines that constant, extract the constant's value, and embed the value in the emitted IL code.

    He goes on to note that this means that you can't get the reference to memory of a constant for this reason. To make this a bit more explicit, in psuedo C# if assembly A defines a const:

    //Assembly A, Class Widget defines this:
    public static const System.Decimal Pi = 3.14
    

    then you have a consumer of A:

    //somewhere in the Program.exe assembly
    decimal myCircleCurcum = 2 * Widget.pi
    

    the resultant compiled IL of program.exe would do something like this pseudocode:

    // pseudo-IL just to illustrate what would happen to the const
    myCircleCurcum = 2*3.14
    

    note that the consuming assembly has no idea that the decimal 3.14 had any relationship to Assembly A at all--it is to program.exe a literal value. This, to me, is a reasonable way for the C# compiler to act--after all, Assembly A declared explicitly that pi is a constant (meaning that the value is once and for all pi=3.14). But, I'd venture to guess, that 99% of C# developers do not understand the ramifications of this & might change pi to be 3.1415 on a whim.

    Constants have a really poor cross-assembly version story (again, this comes from Richter) because a consumer of assembly A with a constant in it will not see a change if assembly A's constant changes (i.e. it was recompiled). This can cause really hard to figure out bugs by consumer of assembly A. . . so much so that I ban my team from using constants. Their slight perf gain is not worth the subtle bugs they can cause.

    You can really only ever use a constant if you know that the value will never, ever change -- and even with something set as a const such as pi, you can't say for sure that you won't want your percision to change in the future.

    if assembly A defines:

    decimal const pi = 3.14
    

    then you build it and then other assemblies consume it, if you then change assembly A:

    decimal const pi = 3.1415
    

    and rebuild assembly A, the consumer of assembly A will still have the old value 3.14! why? because the original 3.14 was defined as a constant which means that the consumers of assembly A have been told that the value won't change--so they can bake that value of pi into their own metadata (if you rebuild consumer of assembly A it will then get the new value of pi in it's metadata). Again, I don't see this as a problem with the way CSC handles constants--it's just that developers probably don't expect that a constant can't be changed safely under some circumstances, where it can be changed safely in others. Safe: no consumers will ever have reference by .dll only (i.e. they will always build from source EVERY TIME), unsafe: consumers don't have a clue about when source code of your assembly with the const defined it it changes. It probably should be made much more clear in .NET documentation that constant means you can't change the value in the sourcecode

    For that reason, I'd strongly suggest not using constants and instead just making the widget readonly. How many values can you really say for certain are truly going to be const for ever and always?

    The only real reason to use const over readonly in my mind is if something might have performance implications... but if you are running into that, I'd wonder if C# is really the correct language for your problem. In short, to me, it is alomst never a good idea to use constants. There are very few times where the tiny perf improvement is worth the potential problems.

    0 讨论(0)
  • 2020-12-05 13:31

    Interesting. I don't know if it is just a limitation of the C# compiler or if it a fundemental limitaion of the language itself.

    To explain what I mean, consider VB.

    In VB 9 you also couldn't infer constants, but this was just a limitation of the compiler. In VB 10 they were able to add constant type inference without making any significant changes the to language.

    0 讨论(0)
提交回复
热议问题