Well, you can use consts in attributes, since they exist as compile time. You can't predict the value of a static readonly variable, since the .cctor
could initialize it from configuration etc.
In terms of usage, constants are burnt into the calling code. This means that if you recompile a library dll to change a public constant, but don't change the consumers, then he consumers will still use the original value. With a readonly variable this won't happen. The flip of this is that constants are (very, very slightly) quicker, since it simply loads the value (rather than having to de-reference it).
Re interning; although you can do this manually, this is most commonly a compiler/runtime feature of literals; if you init a readonly field via a literal:
someField = "abc";
then the "abc"
will be interned. If you read it from config, it won't be. Because a constant string must be a literal, it will also be interned, but it is accessed differently: again, reading from the field is a de-reference, rather than a ldstr
.
public static readonly
fields are a little unusual; public static
properties (with only a get
) would be more common (perhaps backed by a private static readonly
field).
const
values are burned directly into the call-site; this is double edged:
- it is useless if the value is fetched at runtime, perhaps from config
- if you change the value of a const, you need to rebuild all the clients
- but it can be faster, as it avoids a method call...
- ...which might sometimes have been inlined by the JIT anyway
If the value will never change, then const is fine - Zero
etc make reasonable consts ;p Other than that, static
properties are more common.
Best Answer
Apart from the apparent difference of
const
VSreadonly
values can be computed dynamically but need to be assigned before the constructor exits. After that it is frozen.const
's are implicitlystatic
. You use aClassName.ConstantName
notation to access them.There is a subtle difference. Consider a class defined in
AssemblyA
.AssemblyB
referencesAssemblyA
and uses these values in code. When this is compiled:const
value, it is like a find-replace. The value 2 is 'baked into' theAssemblyB
's IL. This means that if tomorrow I updateI_CONST_VALUE
to 20,AssemblyB
would still have 2 till I recompile it.readonly
value, it is like aref
to a memory location. The value is not baked intoAssemblyB
's IL. This means that if the memory location is updated,AssemblyB
gets the new value without recompilation. So ifI_RO_VALUE
is updated to 30, you only need to buildAssemblyA
and all clients do not need to be recompiled.So if you are confident that the value of the constant won't change, use a
const
.But if you have a constant that may change (e.g. w.r.t. precision) or when in doubt, use a
readonly
.Update: Aku needs to get a mention because he pointed this out first. Also I need to plug where I learned this: Effective C# - Bill Wagner