63

We have a project that's compiled into a DLL called consts.dll that contains something like:

public static class Consts
{
    public const string a = "a";
    public const string b = "b";
    public const string c = "c";
}

We have multiple projects of this sort, each compiled into a DLL of the same name (consts.dll) and we replace them according to need. We have another class that uses these consts:

public class ConstsUser 
{
    string f() { return Consts.a; }
}

Unfortunately, Consts.a is optimized to "a" , so even if we replace Consts.dll implementation, we still get "a" instead of the correct value and we need to recompile ConstsUser. Is there anyway to stop the optimizer from replacing const variables with their values?

Shmoopy
  • 5,334
  • 4
  • 36
  • 72
  • 12
    note that it's not an optimizer that is making this replacement, this is just the behavior of the C# compiler in all instances – JaredPar Jan 09 '14 at 14:25
  • 18
    Every public member of a class, including constants, is part of the interface of that class. Constants are special, because not only their names, but also their values are a part of the interface. When you change the interface of a class, you must recompile all its dependent code. Changing a value of a public `const` member is a breaking change. You cannot swap out the DLL, and expect that everything would just work, for the same reason that you would expect a change in a class name or a parameter type of one of its members to trigger an error. – Sergey Kalinichenko Jan 09 '14 at 14:32
  • The answer is also interestingly very good: http://programmers.stackexchange.com/questions/132747/is-having-public-constants-bad#answer-132752 and which again points to http://stackoverflow.com/questions/55984/what-is-the-difference-between-const-and-readonly – Nagaraj Tantri Jan 09 '14 at 14:37
  • 9
    Maybe your constant wasn't so constant after all? Seriously, only use const for things which are actually constant. Pi is a good example. – MattDavey Jan 09 '14 at 17:34
  • 5
    If your constants are not constant, don't use const... Actually, their values should probably not even be in code; they should be in configuration files. – Thomas Levesque Jan 09 '14 at 19:49
  • @MattDavey In my opinion, it is fine to use `const` for stuff that will change in later versions, as long as everyone understands that they will have to recompile all code that refers to the const. It is entirely like introducing new members in (the middle of) an `enum` type. It is fine to make breaking changes as long as everyone knows that is what is happening. – Jeppe Stig Nielsen Jan 10 '14 at 10:07
  • @JeppeStigNielsen I agree that it's a communication issue, but in that case don't you think using the term "constant" is sending the wrong message? Instead of telling everyone "hey this constant might not be constant" why not just make it a public readonly property, that way your intention is clear right from the start. – MattDavey Jan 10 '14 at 11:07
  • @MattDavey That's fine with me. But in some cases, it is clear that the "constant" is varying between releases. For example, to me, it would be fine to have `public const int VersionNumber` or `public const int MaximalNumberOfClientsSupported` and then have this constant change between releases. Of course `static readonly` is fine, but it cannot be used in cases where a literal is required, such as `case` labels in a `switch`, default values of optional parameters, arguments to a an attribute application, and so on. – Jeppe Stig Nielsen Jan 10 '14 at 11:13

2 Answers2

118

I think usage of static readonly modifiers fits your needs:

public static class Consts
{
    public static readonly string a = "a";
    public static readonly string b = "b";
    public static readonly string c = "c";
}

Constants are hard-coded on the call-site, so that is your problem. Static readonly variable can be modified only in variable declaration or static constructor of Consts class, and it will not be inlined on the call-site.

Sergey Berezovskiy
  • 232,247
  • 41
  • 429
  • 459
36

From the book CLR via c#

When code refers to a constant symbol, compilers look up the symbol in the metadata of the assembly that defines the constant, extract the constant’s value, and embed the value in the emitted Intermediate Language (IL) code. Because a constant’s value is embedded directly in code, constants don’t require any memory to be allocated for them at runtime. In addition, you can’t get the address of a constant and you can’t pass a constant by reference. These constraints also mean that constants don’t have a good cross-assembly versioning story, so you should use them only when you know that the value of a symbol will never change.

As we can see, using const does have its benefits when we know that the value of a symbol will never change. It can perform faster because the CLR does not need to resolve the value.

In fact, after building the application assembly, the DLL assembly isn’t even loaded at runtime and can be deleted from the disk because the compiler does not even add a reference to the DLL assembly in the application's metadata.

As already suggested by @Sergey Berezovskiy, we could use static readonly if you need the CLR to resolve the value dynamically at runtime. Performance is affected with this solution, but there is also another benefit.

In addition, a field can be of any data type, so you don’t have to restrict yourself to your compiler’s built-in primitive types (as you do for constants).

Khanh TO
  • 48,509
  • 13
  • 99
  • 115