17
[TestClass]
public class MsProjectIntegration {
    const int? projectID = null;
    // The type 'int?' cannot be declared const
    // ...
}

Why can't I have a const int??

Edit: The reason I wanted a nullable int as a const is because I'm just using it for loading some sample data from a database. If it's null I was just going to initialize sample data at runtime. It's a really quick test project and obviously I could use 0 or -1 but int? just felt like the right data structure for what I wanted to do. readonly seems like the way to go

Markus Jarderot
  • 86,735
  • 21
  • 136
  • 138
Shawn
  • 19,465
  • 20
  • 98
  • 152
  • 12
    Best practice: Use constants only for things which are *logically constant for all eternity*. Good: the number of items in a dozen, the year Elvis was born, the atomic number of lead. Bad: version numbers -- they change from version to version; things which change should not be constants. Terrible: the current yen-to-euro exchange rate; changes every second. – Eric Lippert Dec 02 '09 at 15:48
  • yea i was basically just using it as an ad hoc config file, definitely not best practice – Shawn Dec 02 '09 at 15:59
  • Should that not be "Yea verrily! I was basically . . ." – Binary Worrier Dec 02 '09 at 16:34
  • I really can't think of a case where you would need to have a constant of value null. Could you please enlighten me? – OlliM Dec 02 '09 at 15:25

5 Answers5

20

It's not just nullables; only types built into the runtime can be declared const (from memory, it's bools, the various types of int, floats/doubles, and strings).

Why? Because the value gets embedded directly into the assembly at compile time, and there's no way to embed user-defined types.

The readonly keyword should do what you need, however. By contrast with const, any readonly fields get initialized at runtime rather than compile time, so they can be initialized with more or less any expression you want.

Edit: as Eric Lippert points out, it's not this straightforward. For instance, const decimal works.

This:

private const decimal TheAnswer = 42;

...compiles (well, Reflectors) to this:

[DecimalConstant(0, 0, (uint) 0, (uint) 0, (uint) 42)]
private static readonly decimal TheAnswer;
Tim Robinson
  • 53,480
  • 10
  • 121
  • 138
  • thanks, the assembly part was enlightening and made this the best answer (to me) – Shawn Dec 02 '09 at 15:36
  • 16
    This is not correct. First: decimals are not a built-in type but they can be const. Second: yes, there are ways to embed constant user-defined types; we *chose* to not implement this feature. It's certainly *possible* in principle. (Proof: we did it for decimal.) – Eric Lippert Dec 02 '09 at 15:44
  • 2
    ha, when i asked this question i wasn't expecting a response from someone from the c# compiler team – Shawn Dec 02 '09 at 15:49
  • 4
    This is one of the reasons why stackoverflow is so badass. –  Dec 02 '09 at 16:02
  • @EricLippert if decimal isn't built in type, how is compiler able to infer its value and do simple checks right at compile time? ie if you do `const decimal d = 0;` and `if(d == 1)...` the compiler warns that `if` is always false. The value comparison is made right there. – nawfal Dec 14 '13 at 05:06
  • @nawfsl decimal is special in c#. But from the clr point of view it is just another struct. – Eric Lippert Dec 14 '13 at 18:12
  • 1
    One wonders what makes the items in the "allowed as const" list so special; other immutable types besides String should be perfectly okay to use as const. Like Color and DateTime; both of those are basically just wrappers around a bare int too, after all (respectively an Int32 and an Int64). – Nyerguds Dec 06 '16 at 09:07
13

http://en.csharp-online.net/const,_static_and_readonly

Constants must be of an integral type (sbyte, byte, short, ushort, int, uint, long, ulong, char, float, double, decimal, bool, or string), an enumeration, or a reference to null.

Since classes or structures are initialized at run time with the new keyword, and not at compile time, you can't set a constant to a class or structure.

Since nullable is a struct, the above quote is the reason why.

Blake Pettersson
  • 8,927
  • 3
  • 27
  • 36
9

You can't have a const reference type (or a struct), therefore you can't have a const int? which is really just a Nullable<int>.

You can mark it as readonly

readonly int? projectID = null;

Then it can't be modified outside the class constructors.

Binary Worrier
  • 50,774
  • 20
  • 136
  • 184
3

You may want to consider using the "readonly" modifier instead.

consts are evaluated at compile time, whereas readonlys are enforced at run time. Instances of complex types cannot be compiled into the assembly, and so must be created at runtime.

John Gietzen
  • 48,783
  • 32
  • 145
  • 190
2

You're basically saying:

I have a class with a projectId field that may or may not have a value, but that in fact NEVER has a value, it's is always undefined.

From a logical point of view... the declaration itself makes no sense.

Jorge Córdoba
  • 51,063
  • 11
  • 80
  • 130
  • because its a config setting that could be null and i would rather not code around a magic number.... say -1 – Shawn Dec 02 '09 at 15:34
  • If projectId is "const" you cannot be loading anything into it from the database... in fact you can't do almost anything with it. – Jorge Córdoba Dec 02 '09 at 15:42
  • How can a primary key be null? – Jorge Córdoba Dec 02 '09 at 15:52
  • var project = projectID.HasValue ? Project.GetProjectByID(projectID.Value, connectionString) : new Project(); – Shawn Dec 02 '09 at 15:58
  • 1
    Sure it makes sense. For example, in a unit test that uses DataRowAttribute. I'd like to declare my test data like private const int? NullStudentId = null; private const int ZeroStudentId = 0; private const int ValidStudentId = 100; Then in [DataRow] use my consts (cannot use readonly must be const) like [DataRow[NullStudentId)] [DataRow(ZeroStudentId)] [DataRow(ValidStudentId)] Unfortunately I cannot do that. I need to use null instead of NullStudentId. That's one valid use of a const int?. – Gilbert Mar 08 '18 at 02:40