Ccna final exam - java, php, javascript, ios, cshap all in one. This is a collaboratively edited question and answer site for professional and enthusiast programmers. It's 100% free, no registration required.
Sunday, May 20, 2012
What is the difference between const and readonly?
What is the difference between const and readonly and do you use one over the other?
having to declare the value at the time of a definition for a const VS readonly values can be computed dynamically but need to be assigned before the ctor exits.. after that it is frozen. 'const's are implicitly static. You use a ClassName.ConstantName notation to access them.
There is a subtle difference. Consider a class defined in AssemblyA.
public class Const_V_Readonly { public const int I_CONST_VALUE = 2; public readonly int I_RO_VALUE; public Const_V_Readonly() { I_RO_VALUE = 3; } }
AssemblyB references AssemblyA and uses these values in code. When this is compiled,
in the case of the const value, it is like a find-replace, the value 2 is 'baked into' the AssemblyB's IL. This means that tomorrow if I update I_CONST_VALUE to 20 in the future. Assembly B would still have 2 till I recompile it. in the case of the readonly value, it is like a ref to a memory location. The value is not baked into AssemblyB's IL. This means that if the memory location is updated, Assembly B gets the new value without recompilation. So if I_RO_VALUE is updated to 30, you only need to build AssemblyA. 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.
public const int CM_IN_A_METER = 100;
But if you have a constant that may change (e.g. w.r.t. precision).. or when in doubt, use a readonly.
public readonly float PI = 3.14;
Update: Aku needs to get a mention coz he pointed this out first. Also I need to plug where I learned this.. Effective C# - Bill Wagner
There is a gotcha with consts! If you reference constant from other assembly it's value will be compiled right into calling assembly. That way when you update constant in referenced assembly it won't change in calling assembly!
This explains it. Summary: const must be initialized at declaration time, readonly can be initialized on the constructor (and thus have a different value depending on the constructor used).
EDIT: See Gishu's gotcha above for the subtle difference
Constants are static by default They must have a value at compilation-time (you can have e.g. 3.14 * 2, but cannot call methods) Could be declared within functions Are copied into every assembly that uses them (every assembly gets a local copy of values) Can be used in attributes
Readonly instance fields
Must have set value, by the time constructor exits Are evaluated when instance is created
Static readonly fields
Are evaluated when code execution hits class reference (when new instance is created or a static method is executed) Must have an evaluated value by the time the static constructor is done It's not recommended to put ThreadStaticAttribute on these (static constructors will be executed in one thread only and will set the value for its thread; all other threads will have this value uninitialized)
Just to add, ReadOnly for reference types only makes the reference readonly not the values. For example:
public class Const_V_Readonly { public const int I_CONST_VALUE = 2; public readonly char[] I_RO_VALUE = new Char[]{'a', 'b', 'c'};
public UpdateReadonly() { I_RO_VALUE[0] = 'V'; //perfectly legal and will update the value I_RO_VALUE = new char[]{'V'}; //will cause compiler error } }
A const is a compile-time constant whereas readonly allows a value to be calculated at run-time and set in the constructor or field initializer. So, a 'const' is always constant but 'readonly' is read-only once it is assigned.
Eric Lippert of the C# team has more information on different types of immutability
There is a small gotcha with readonly. A readonly field can be set multiple times within the constructor(s). Even if the value is set in two different chained constructors it is still allowed.
public class Sample { private readonly string ro;
public Sample() { ro = "set"; }
public Sample(string value) : this() { ro = value; // this works even though it was set in the no-arg ctor } }
Here's another link demonstrating how const isn't version safe, or relevant for reference types.
Summary:
The value of your const property is set at compile time and can't change at runtime Const can't be marked as static - the keyword denotes they are static, unlike readonly fields which can. Const can't be anything except value (primitive) types The readonly keyword marks the field as unchangeable. However the property can be changed inside the constructor of the class The readonly only keyword can also be combined with static to make it act in the same way as a const (atleast on the surface). There is a marked difference when you look at the IL between the two const fields are marked as "literal" in IL while readonly is "initonly"
Variables marked const are little more than strongly typed #define macros, at compile time const variable references are replaced with inline literal values. As a consequence only certain built-in primitive value types can be used in this way. Variables marked readonly can be set, in a constructor, at run-time and their read-only-ness is enforced during run-time as well. There is some minor performance cost associated with this but it means you can use readonly with any type (even reference types).
Also, const variables are inherently static, whereas readonly variables can be instance specific if desired.
You can use const variables as input to attribute constructors but not readonly variables.
Example:
public static class Text { public const string ConstDescription = "This can be used."; public readonly static string ReadonlyDescription = "Cannot be used."; }
public class Foo { [Description(Text.ConstDescription)] public int BarThatBuilds { { get; set; } }
[Description(Text.ReadOnlyDescription)] public int BarThatDoesNotBuild { { get; set; } } }
Another gotcha. Since const really only works with basic data types, if you want to work with a class, you may feel "forced" to use ReadOnly. However, beware of the trap! ReadOnly means that you can not replace the object with another object (you can't make it refer to another object). But any process that has a reference to the object is free to modify the values inside the object! So don't be confused into thinking that ReadOnly implies a user can't change things. There is no simple syntax in C# to prevent an instantiation of a class from having its internal values changed (as far as I know).
One of the team members in our office provided the following guidance on when to use const, static, and readonly:
Use const when you have a variable of a type you can know at runtime (string literal, int, double, enums,...) that you want all instances or consumers of a class to have access to where the value should not change. Use static when you have data that you want all instances or consumers of a class to have access to where the value can change. Use static readonly when you have a variable of a type that you cannot know at runtime (objects) that you want all instances or consumers of a class to have access to where the value should not change. Use readonly when you have an instance level variable you will know at the time of object creation that should not change.
One final note: a const field is static, but the inverse is not true.
Principally; you can assign a value to a static readonly field to a non-constant value at runtime, whereas a const has to be assigned a constant value.
A constant will be compiled into the consumer as a literal value while the static string will serve as a reference to the value defined.
As an exercise, try creating an external library and consume it in a console application, then alter the values in the library and recompile it (without recompiling the consumer program), drop the DLL into the directory and run the EXE manually, you should find that the constant string does not change.
I believe a const value is the same for all objects (and must be initialized with a literal expression), whereas readonly can be different for each instantiation...
One thing to add to what people have said above. If you have an assembly containing a readonly value (e.g. readonly MaxFooCount = 4; ), you can change the value that calling assemblies see by shipping a new version of that assembly with a different value (e.g. readonly MaxFooCount = 5;)
But with a const, it would be folded into the caller's code when the caller was compiled.
If you've reached this level of C# proficiency, you are ready for Bill Wagner's book, Effective C#: 50 Specific Ways to Improve Your C# Which answers this question in detail, (and 49 other things).
The key difference is that Const is the C equivalent of #DEFINE. The number literally gets substituted a-la precompiler. Readonly is actually treated as a variable.
This distinction is especially relevant when you have Project A depending on a Public constant from Project B. Suppose the public constant changes. Now your choice of const/readonly will impact the behavior on project A:
Const: project A does not catch the new value (unless it is recompiled with the new const, of course) because it was compiled with the constants subtituted in.
ReadOnly: Project A will always ask project B for it's variable value, so it will pick up the new value of the public constant in B.
Honestly, I would recommend you use readonly for nearly everything except truly universal constants ( e.g. Pi, Inches_To_Centimeters). For anything that could possibly change, I say use readonly.
Apart from the apparent diff of
ReplyDeletehaving to declare the value at the time of a definition for a const VS readonly values can be computed dynamically but need to be assigned before the ctor exits.. after that it is frozen.
'const's are implicitly static. You use a ClassName.ConstantName notation to access them.
There is a subtle difference. Consider a class defined in AssemblyA.
public class Const_V_Readonly
{
public const int I_CONST_VALUE = 2;
public readonly int I_RO_VALUE;
public Const_V_Readonly()
{
I_RO_VALUE = 3;
}
}
AssemblyB references AssemblyA and uses these values in code. When this is compiled,
in the case of the const value, it is like a find-replace, the value 2 is 'baked into' the AssemblyB's IL. This means that tomorrow if I update I_CONST_VALUE to 20 in the future. Assembly B would still have 2 till I recompile it.
in the case of the readonly value, it is like a ref to a memory location. The value is not baked into AssemblyB's IL. This means that if the memory location is updated, Assembly B gets the new value without recompilation. So if I_RO_VALUE is updated to 30, you only need to build AssemblyA. 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.
public const int CM_IN_A_METER = 100;
But if you have a constant that may change (e.g. w.r.t. precision).. or when in doubt, use a readonly.
public readonly float PI = 3.14;
Update: Aku needs to get a mention coz he pointed this out first. Also I need to plug where I learned this.. Effective C# - Bill Wagner
There is a gotcha with consts! If you reference constant from other assembly it's value will be compiled right into calling assembly. That way when you update constant in referenced assembly it won't change in calling assembly!
ReplyDeleteThis explains it. Summary: const must be initialized at declaration time, readonly can be initialized on the constructor (and thus have a different value depending on the constructor used).
ReplyDeleteEDIT: See Gishu's gotcha above for the subtle difference
Constants
ReplyDeleteConstants are static by default
They must have a value at compilation-time (you can have e.g. 3.14 * 2, but cannot call methods)
Could be declared within functions
Are copied into every assembly that uses them (every assembly gets a local copy of values)
Can be used in attributes
Readonly instance fields
Must have set value, by the time constructor exits
Are evaluated when instance is created
Static readonly fields
Are evaluated when code execution hits class reference (when new instance is created or a static method is executed)
Must have an evaluated value by the time the static constructor is done
It's not recommended to put ThreadStaticAttribute on these (static constructors will be executed in one thread only and will set the value for its thread; all other threads will have this value uninitialized)
Just to add, ReadOnly for reference types only makes the reference readonly not the values. For example:
ReplyDeletepublic class Const_V_Readonly
{
public const int I_CONST_VALUE = 2;
public readonly char[] I_RO_VALUE = new Char[]{'a', 'b', 'c'};
public UpdateReadonly()
{
I_RO_VALUE[0] = 'V'; //perfectly legal and will update the value
I_RO_VALUE = new char[]{'V'}; //will cause compiler error
}
}
A const is a compile-time constant whereas readonly allows a value to be calculated at run-time and set in the constructor or field initializer. So, a 'const' is always constant but 'readonly' is read-only once it is assigned.
ReplyDeleteEric Lippert of the C# team has more information on different types of immutability
There is a small gotcha with readonly. A readonly field can be set multiple times within the constructor(s). Even if the value is set in two different chained constructors it is still allowed.
ReplyDeletepublic class Sample {
private readonly string ro;
public Sample() {
ro = "set";
}
public Sample(string value) : this() {
ro = value; // this works even though it was set in the no-arg ctor
}
}
Here's another link demonstrating how const isn't version safe, or relevant for reference types.
ReplyDeleteSummary:
The value of your const property is set at compile time and can't change at runtime
Const can't be marked as static - the keyword denotes they are static, unlike readonly fields which can.
Const can't be anything except value (primitive) types
The readonly keyword marks the field as unchangeable. However the property can be changed inside the constructor of the class
The readonly only keyword can also be combined with static to make it act in the same way as a const (atleast on the surface). There is a marked difference when you look at the IL between the two
const fields are marked as "literal" in IL while readonly is "initonly"
Variables marked const are little more than strongly typed #define macros, at compile time const variable references are replaced with inline literal values. As a consequence only certain built-in primitive value types can be used in this way. Variables marked readonly can be set, in a constructor, at run-time and their read-only-ness is enforced during run-time as well. There is some minor performance cost associated with this but it means you can use readonly with any type (even reference types).
ReplyDeleteAlso, const variables are inherently static, whereas readonly variables can be instance specific if desired.
Yet another gotcha: readonly values can be changed by "devious" code via reflection.
ReplyDeletevar fi = this.GetType().BaseType.GetField("_someField", BindingFlags.Instance | BindingFlags.NonPublic);
fi.SetValue(this, 1);
Can I change a private readonly inherited field in C# using reflection?
Constant : Can't be changed anywhere.
ReplyDeleteRead only : This value can only be change in the contstructor. Can't be change in normal functions.
You can use const variables as input to attribute constructors but not readonly variables.
ReplyDeleteExample:
public static class Text {
public const string ConstDescription = "This can be used.";
public readonly static string ReadonlyDescription = "Cannot be used.";
}
public class Foo
{
[Description(Text.ConstDescription)]
public int BarThatBuilds {
{ get; set; }
}
[Description(Text.ReadOnlyDescription)]
public int BarThatDoesNotBuild {
{ get; set; }
}
}
Another gotcha.
ReplyDeleteSince const really only works with basic data types, if you want to work with a class, you may feel "forced" to use ReadOnly. However, beware of the trap! ReadOnly means that you can not replace the object with another object (you can't make it refer to another object). But any process that has a reference to the object is free to modify the values inside the object!
So don't be confused into thinking that ReadOnly implies a user can't change things. There is no simple syntax in C# to prevent an instantiation of a class from having its internal values changed (as far as I know).
One of the team members in our office provided the following guidance on when to use const, static, and readonly:
ReplyDeleteUse const when you have a variable of a type you can know at runtime (string literal, int, double, enums,...) that you want all instances or consumers of a class to have access to where the value should not change.
Use static when you have data that you want all instances or consumers of a class to have access to where the value can change.
Use static readonly when you have a variable of a type that you cannot know at runtime (objects) that you want all instances or consumers of a class to have access to where the value should not change.
Use readonly when you have an instance level variable you will know at the time of object creation that should not change.
One final note: a const field is static, but the inverse is not true.
Principally; you can assign a value to a static readonly field to a non-constant value at runtime, whereas a const has to be assigned a constant value.
ReplyDeleteA constant will be compiled into the consumer as a literal value while the static string will serve as a reference to the value defined.
ReplyDeleteAs an exercise, try creating an external library and consume it in a console application, then alter the values in the library and recompile it (without recompiling the consumer program), drop the DLL into the directory and run the EXE manually, you should find that the constant string does not change.
I believe a const value is the same for all objects (and must be initialized with a literal expression), whereas readonly can be different for each instantiation...
ReplyDeleteI fully aggree with Gishu's answer. As a rule of thumb, to make my life easier I use const only for private members.
ReplyDeleteOne thing to add to what people have said above. If you have an assembly containing a readonly value (e.g. readonly MaxFooCount = 4; ), you can change the value that calling assemblies see by shipping a new version of that assembly with a different value (e.g. readonly MaxFooCount = 5;)
ReplyDeleteBut with a const, it would be folded into the caller's code when the caller was compiled.
If you've reached this level of C# proficiency, you are ready for Bill Wagner's book, Effective C#: 50 Specific Ways to Improve Your C#
Which answers this question in detail, (and 49 other things).
The key difference is that Const is the C equivalent of #DEFINE. The number literally gets substituted a-la precompiler. Readonly is actually treated as a variable.
ReplyDeleteThis distinction is especially relevant when you have Project A depending on a Public constant from Project B. Suppose the public constant changes. Now your choice of const/readonly will impact the behavior on project A:
Const: project A does not catch the new value (unless it is recompiled with the new const, of course) because it was compiled with the constants subtituted in.
ReadOnly: Project A will always ask project B for it's variable value, so it will pick up the new value of the public constant in B.
Honestly, I would recommend you use readonly for nearly everything except truly universal constants ( e.g. Pi, Inches_To_Centimeters). For anything that could possibly change, I say use readonly.
Hope this helps,
Alan.
A const has to be hard-coded, where as readonly can be set in the constructor of the class.
ReplyDelete