'Static readonly' vs. 'const' - c#

I've read around about const and static readonly fields. We have some classes which contain only constant values. They are used for various things around in our system. So I am wondering if my observation is correct:
Should these kind of constant values always be static readonly for everything that is public? And only use const for internal/protected/private values?
What do you recommend? Should I maybe even not use static readonly fields, but rather use properties maybe?

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.

I would use static readonly if the Consumer is in a different assembly. Having the const and the Consumer in two different assemblies is a nice way to shoot yourself in the foot.

A few more relevant things to be noted:
const int a
must be initialized.
initialization must be at compile time.
readonly int a
can use a default value, without initializing.
initialization can be done at run time (Edit: within constructor only).

This is just a supplement to the other answers. I will not repeat them (now four years later).
There are situations where a const and a non-const have different semantics. For example:
const int y = 42;
static void Main()
{
short x = 42;
Console.WriteLine(x.Equals(y));
}
prints out True, whereas:
static readonly int y = 42;
static void Main()
{
short x = 42;
Console.WriteLine(x.Equals(y));
}
writes False.
The reason is that the method x.Equals has two overloads, one that takes in a short (System.Int16) and one that takes an object (System.Object). Now the question is whether one or both apply with my y argument.
When y is a compile-time constant (literal), the const case, it becomes important that there does exist an implicit conversion from int to short provided that the int is a constant, and provided that the C# compiler verifies that its value is within the range of a short (which 42 is). See Implicit constant expression conversions in the C# Language Specification. So both overloads have to be considered. The overload Equals(short) is preferred (any short is an object, but not all object are short). So y is converted to short, and that overload is used. Then Equals compares two short of identical value, and that gives true.
When y is not a constant, no implicit conversion from int to short exists. That's because in general an int may be too huge to fit into a short. (An explicit conversion does exist, but I didn't say Equals((short)y), so that's not relevant.) We see that only one overload applies, the Equals(object) one. So y is boxed to object. Then Equals is going to compare a System.Int16 to a System.Int32, and since the run-time types do not even agree, that will yield false.
We conclude that in some (rare) cases, changing a const type member to a static readonly field (or the other way, when that is possible) can change the behavior of the program.

One thing to note is const is restricted to primitive/value types (the exception being strings).

Static Read Only:
The value can be changed through a static constructor at runtime. But not through a member function.
Constant:
By default static. A value cannot be changed from anywhere (constructor, function, runtime, etc. nowhere).
Read Only:
The value can be changed through a constructor at runtime. But not through a member function.
You can have a look at my repository: C# property types.

The readonly keyword is different from the const keyword. A const field can only be initialized at the declaration of the field. A readonly field can be initialized either at the declaration or in a constructor. Therefore, readonly fields can have different values depending on the constructor used. Also, while a const field is a compile-time constant, the readonly field can be used for runtime constants
From this short and clear MSDN reference.

const and readonly are similar, but they are not exactly the same.
A const field is a compile-time constant, meaning that that value can be computed at compile-time. A readonly field enables additional scenarios in which some code must be run during construction of the type. After construction, a readonly field cannot be changed.
For instance, const members can be used to define members like:
struct Test
{
public const double Pi = 3.14;
public const int Zero = 0;
}
Since values like 3.14 and 0 are compile-time constants. However, consider the case where you define a type and want to provide some pre-fab instances of it. E.g., you might want to define a Color class and provide "constants" for common colors like Black, White, etc. It isn't possible to do this with const members, as the right hand sides are not compile-time constants. One could do this with regular static members:
public class Color
{
public static Color Black = new Color(0, 0, 0);
public static Color White = new Color(255, 255, 255);
public static Color Red = new Color(255, 0, 0);
public static Color Green = new Color(0, 255, 0);
public static Color Blue = new Color(0, 0, 255);
private byte red, green, blue;
public Color(byte r, byte g, byte b) => (red, green, blue) = (r, g, b);
}
But then there is nothing to keep a client of Color from mucking with it, perhaps by swapping the Black and White values. Needless to say, this would cause consternation for other clients of the Color class. The "readonly" feature addresses this scenario.
By simply introducing the readonly keyword in the declarations, we preserve the flexible initialization while preventing client code from mucking around.
public class Color
{
public static readonly Color Black = new Color(0, 0, 0);
public static readonly Color White = new Color(255, 255, 255);
public static readonly Color Red = new Color(255, 0, 0);
public static readonly Color Green = new Color(0, 255, 0);
public static readonly Color Blue = new Color(0, 0, 255);
private byte red, green, blue;
public Color(byte r, byte g, byte b) => (red, green, blue) = (r, g, b);
}
It is interesting to note that const members are always static, whereas a readonly member can be either static or not, just like a regular field.
It is possible to use a single keyword for these two purposes, but this leads to either versioning problems or performance problems. Assume for a moment that we used a single keyword for this (const) and a developer wrote:
public class A
{
public static const C = 0;
}
and a different developer wrote code that relied on A:
public class B
{
static void Main() => Console.WriteLine(A.C);
}
Now, can the code that is generated rely on the fact that A.C is a compile-time constant? I.e., can the use of A.C simply be replaced by the value 0? If you say "yes" to this, then that means that the developer of A cannot change the way that A.C is initialized -- this ties the hands of the developer of A without permission.
If you say "no" to this question then an important optimization is missed. Perhaps the author of A is positive that A.C will always be zero. The use of both const and readonly allows the developer of A to specify the intent. This makes for better versioning behavior and also better performance.

My preference is to use const whenever I can, which, as mentioned in previous answers, is limited to literal expressions or something that does not require evaluation.
If I hit up against that limitation, then I fallback to static readonly, with one caveat. I would generally use a public static property with a getter and a backing private static readonly field as Marc mentions here.

Const: Constant variable values have to be defined along with the declaration and after that it won't change.const are implicitly static, so without creating a class instance we can access them. This has a value at compile time.
ReadOnly: We can define read-only variable values while declaring as well as using the constructor at runtime. Read-only variables can't access without a class instance.
Static readonly: We can define static readonly variable values while declaring as well as only through a static constructor, but not with any other constructor. We can also access these variables without creating a class instance (as static variables).
Static readonly will be better choice if we have to consume the variables in different assemblies. Please check the full details in the below blog post:
Const Strings – a very convenient way to shoot yourself in the foot

A static readonly field is advantageous when exposing to
other assemblies a value that might change in a later version.
For instance, suppose assembly X exposes a constant as follows:
public const decimal ProgramVersion = 2.3;
If assembly Y references X and uses this constant, the value 2.3
will be baked into assembly Y when compiled. This means that
if X is later recompiled with the constant set to 2.4, Y will still
use the old value of 2.3 until Y is recompiled. A static
readonly field avoids this problem.
Another way of looking at this is that any value that might
change in the future is not constant by definition, and so should
not be represented as one.

Const: Const is nothing but "constant", a variable of which the value is constant but at compile time. And it's mandatory to assign a value to it. By default a const is static and we cannot change the value of a const variable throughout the entire program.
Static ReadOnly: A Static Readonly type variable's value can be assigned at runtime or assigned at compile time and changed at runtime. But this variable's value can only be changed in the static constructor. And cannot be changed further. It can change only once at runtime
Reference: c-sharpcorner

There is a minor difference between const and static readonly fields in C#.Net
const must be initialized with value at compile time.
const is by default static and needs to be initialized with constant value, which can not be modified later on.
It can not be used with all datatypes. For ex- DateTime. It can not be used with DateTime datatype.
public const DateTime dt = DateTime.Today; //throws compilation error
public const string Name = string.Empty; //throws compilation error
public static readonly string Name = string.Empty; //No error, legal
readonly can be declared as static, but not necessary. No need to initialize at the time of declaration. Its value can be assigned or changed using constructor once. So there is a possibility to change value of readonly field once (does not matter, if it is static or not), which is not possible with const.

const:
value should be given upon declaration
compile time constant
readonly:
value can be given upon declaration or during runtime using constructors.The value may vary depend upon the constructor used.
run time constant

A const (being determined at compile-time) can be used in cases where a readonly static can't, like in switch statements, or attribute constructors. This is because readonly fields are only resolved at run-time, and some code constructs require compile time assurance. A readonly static can be calculated in a constructor, which is often an essential and useful thing. The difference is functional, as should be their usage in my opinion.
In terms of memory allocation, at least with strings (being a reference type), there seems to be no difference in that both are interned and will reference the one interned instance.
Personally, my default is readonly static, as it makes more semantic and logical sense to me, especially since most values are not needed at compile time. And, by the way, public readonly statics are not unusual or uncommon at all as the marked answer states: for instance, System.String.Empty is one.

Another difference between declaring const and static readonly is in memory allocation.
A static field belongs to the type of an object rather than to an instance of that type. As a result, once the class is referenced for the first time, the static field would "live" in the memory for the rest of time, and the same instance of the static field would be referenced by all instances of the type.
On the other hand, a const field "belongs to an instance of the type.
If memory of deallocation is more important for you, prefer to use const. If speed, then use static readonly.

Use const if you can provide a compile-time constant:
private const int Total = 5;
Use static readonly if you need your value evaluated during run-time:
private static readonly int GripKey = Animator.StringToHash("Grip");
This will give a compile error because it is impossible to get the value at compile-time.
private const int GripKey = Animator.StringToHash("Grip");

Constants are like the name implies, fields which don't change and are usually defined statically at compile time in the code.
Read-only variables are fields that can change under specific conditions.
They can be either initialized when you first declare them like a constant, but usually they are initialized during object construction inside the constructor.
They cannot be changed after the initialization takes place, in the conditions mentioned above.
Static read-only sounds like a poor choice to me since, if it's static and it never changes, so just use it public const. If it can change then it's not a constant and then, depending on your needs, you can either use read-only or just a regular variable.
Also, another important distinction is that a constant belongs to the class, while the read-only variable belongs to the instance!

Const
Can be applied only for fields. Value should be in code compile time.
Suited for removing magic "strings","int/double", (primitive types) etc across the code which is known already before compiling the code.
After compiling the value will be placed all over the compiled code wherever constant is used. So if you have a huge string used many places, then watch out before making it const. consider using static read only.
Static read only
Static read only be applied for fields/props and static can be used for methods.
(on side note)When static is applied to methods, the complied code does not pass the 'this' parameter to the method and hence you cannot access the instance data of the object.
Suitable for values which may change after compiling the code. Like values initialized from configuration, during startup of application etc.
After compiling the code, the ref to value is used in IL code and may be slower compared to using const, but compiled code is small
During Refactoring, All const can be safely converted to Static read only, but not vise versa as we have seen above when converted code may break as some static readonly variable could be initialized in constructors.

There is one important question, that is not mentioned anywhere in the above answers, and should drive you to prefer "const" especially for basic types like "int", "string" etc.
Constants can be used as Attribute parameters, static readonly field not!
Azure functions HttpTrigger, not using HttpMethods class in attribute
If only microsoft used constants for Http's GET, POST, DELETE etc.
It would be possible to write
[HttpTrigger(AuthorizationLeve.Anonymous, HttpMethods.Get)] // COMPILE ERROR: static readonly,
But instead I have to resort to
[HttpTrigger(AuthorizationLeve.Anonymous, "GET")] // STRING
Or use my own constant:
public class HttpConstants
{
public const string Get = "GET";
}
[HttpTrigger(AuthorizationLeve.Anonymous, HttpConstants.Get)] // Compile FINE!

One additional difference that I don't believe is mentioned above:
const and static readonly values don't get CodeLens applied to them in the Visual Studio IDE.
static get only properties DO get CodeLens applied to them.
I consider the addition of CodeLens to be quite valuable.
Note: Currently using Visual Studio 2022.

Const, readonly, static readonly - keywords that perform a similar action but have an important difference:
• Const - is a variable whose value is constant and is assigned at compile time. You must assign a value to it. The default constants are static, and we cannot change the value of the const variable throughout the program.
• Readonly - means a value that we can change at run time, or we can assign it at run time, but only through a non-static constructor.
• Static readonly - values ​​can be assigned at run time or assigned at compile time and changed at run time. But the value of this variable can be changed only in the static constructor. And cannot be changed further. It can only be changed once during execution.
Examples you can find here - https://www.c-sharpcorner.com/UploadFile/c210df/difference-between-const-readonly-and-static-readonly-in-C-Sharp/

Related

How can I get the number of enums as a constant?

From Total number of items defined in an enum, I see I can get the number of enums by using:
Enum.GetNames(typeof(Item.Type)).Length;
Works great!
But, I need this number as a constant number, so that I can use it in Unity's [Range(int, int)] feature.
private const int constEnumCount = Enum.GetNames(typeof(Item.Type)).Length;
The above does not work, because the enum count is not a constant number, so I cannot assign it to a constant variable.
How can I get the number of enums as a constant?
It's not possible to get the number of enums as a const. Enum.GetNames uses reflection to get these things, and that's inherently a runtime operation. Therefore, it can't be known at compile time, which is a requirement for being const.
Unfortunately, this is not possible to do in any meaningful way due to technical limitations:
[Range(int,int)] is an attribute, and all information provided to an attribute has to be a const
The only truly bulletproof way to get the number of values in an enum is to use Enum.GetValues(typeof(MyEnum)).Length or the Enum.GetNames(typeof(MyEnum)).Length, both of which are run time reflection.
However, there are hacks that can sort of work. For example, the value of an enum can be cast to an integer. As long as nobody is explicitly defining values for your enums you can use the last element in your enum kind of like this:
[Range(0,(int)MyEnum.LastValue)]
public void BlahBlahBlah() {}
However, know that as soon as someone adds a new entry to the enum after the one you are using or reorders the elements in the enum, your code will break unpredictably and not behave like you want.
It's sad, but the C# compiler is not smart enough to do simple math in the compiler like Java, C, and C++ compilers. So even the example I gave would only really work if the LastValue wasn't ever used for anything except to mark the last element in the enum. It lowers the complexity of the C# compiler, which also greatly improves the compilation speed for your application. As such, there are some trade-offs that the C# and CLR team took to improve your experience in other places.
Assuming that you need a const because you are trying to specify the values for an Attribute (this one?) then you are out of luck.
Your options are:
Hardcode the count in the attribute declaration or as a const itself and be careful to keep the count in sync with the enum definition
Use PostSharp or some other aspect oriented framework to insert the attribute for you. Have never done this myself but it looks possible (How to inject an attribute using a PostSharp attribute?)
You could probably also finagle some way to so this with T4 templates but that would get excessively kludgy.
Were it me, unless you are talking but hundreds of different set of enumerations, I'd hardcode the length and maybe add an Assert where I needed it.
// WARNING - if you add members update impacted Range attributes
public enum MyEnum
{
foo,
bar,
baz
}
[Range(0, 3)]
class Test
{
public Test()
{
int enumCount = Enum.GetNames(typeof(MyEnum)).Length;
int rangeMax = GetType().GetCustomAttributes(typeof(Range), false).OfType<Range>().First().Max;
Debug.Assert(enumCount == rangeMax);
}
static void Main(string[] args)
{
var test = new Test();
}
}
Super late to the game here but I've always used a nifty hack when using enum defaults (i.e. no custom values).
public enum MyEnum {
foo,
bar,
baz,
count
}
Since enums default to starting with 0, ensuring the last entry is named simply 'count' ensures that the value of count is in fact the number of values in the enum itself.
private const int constEnumCount = (int)MyEnum.count;
Cheers!
You cannot assign/create a const at runtime. That is what you are trying to do. A const has to be fully evaluated at compile time, not runtime.
I am not sure about Unity (and why it requires a const), but I would look for using readonly
private readonly int constEnumCount = Enum.GetNames(typeof(Item.Type)).Length;
In C#, a const is defined as constant, i.e. the value (not the calculation which produced it!) is directly embedded in the compiled assembly.
To stop you from doing something problematic, the compiler does not allow you to assign the result of a calculation to a const. To understand why, imagine it were possible:
A.dll
public enum Foo { A, B }
B.dll
public const NumberOfFoos = Enum.GetNames(typeof(Foo)).Length;
// Compiles to:
B.dll
public const NumberOfFoos = 2;
Now you change A.dll:
A.dll
public enum Foo { A, B, C, D }
B.dll
public const NumberOfFoos = 2; // Oh no!
So you would need to recompile B.dll to get the correct value.
It gets worse: Imagine you had an assembly C.dll, which uses B.NumberOfFoos. The value 2 would be directly embedded in C.dll, so it also would need to be recompiled, after B.dll, in order to get the correct value. Therefore (pit of success), C# does not allow you to do that assignment to a const.

What's the idea behind allowing private constant to be used as default parameters for public methods?

To my surprise, this one compiles and runs:
class Program
{
static void Main()
{
DoSomething();
}
private const int DefaultValue = 2; // <-- Here, private.
public static void DoSomething(int value = DefaultValue)
{
Console.WriteLine(value);
}
}
The method is public whereas the default value "redirects" to a constant private variable.
My question:
What is/was the idea behind this "concept"?
My understanding (until today) was, that something public can only be used if all other "referenced" elements are also public.
Update:
I just ILSpy-decompiled my class to find:
static class Program
{
private static void Main()
{
Program.DoSomething(2);
}
private const int DefaultValue = 2;
public static void DoSomething(int value = 2)
{
Console.WriteLine(value);
}
}
So if the private constant as a default parameter is being done in e.g. a library, the user of the library still sees the default parameter.
What is/was the idea behind this "concept"?
The idea is that as const value is static and never changes - you can use it as default value for method's optional parameters same as you can use normal values. A quote from MSDN :
Each optional parameter has a default value as part of its definition. If no argument is sent for that parameter, the default value is used. A default value must be one of the following types of expressions:
a constant expression;
an expression of the form new ValType(), where ValType is a value
type, such as an enum or a struct;
an expression of the form default(ValType), where ValType is a value
type.
My understanding (until today) was, that something public can only be
used if all other "referenced" elements are also public
Well technically speaking it's correct. But in your scenario both members are accessible as they are defined in the same class however should const in our case be defined outside of class Program it'd be inaccessible inside class Program.
The name DefaultValue is private, but the number 2 is still the number 2.
Because DefaultValue is private, we cannot access Program.DefaultValue from outside of Program. Presumably we wouldn't particularly want to.
And because we've bothered to define DefaultValue at all, it's presumably something that we do care about when we are working on how Program works.
So when we come to define a default value for DoSomething there's presumably some logical reason why the value we want there happens to be the same as the value DefaultValue.
And as such, it's presumably beneficial to be able to use that constant there, for much the same reasons as we would find constants beneficial anywhere.
And since DefaultValue is just a Program-specific way of saying 2, there's no real reason why we can't.
Of course, the metadata would reflect this as 2 rather than the (meaningless to the outside) DefaultValue, but then that would hold if the const was public anyway (the metadata about default values gives only the value, not whether or not it related to any defined constants).
So there's no downside.
So considering that:
There's an advantage to the implementer.
There's no disadvantage to the user, over just a use of a literal 2.
Preventing it would have to introduce a special rule to be an exception to the rule that defined constants can be used anywhere a constant value from a literal can.
Why not?
When you use const, the compiler replaces all the occurrences of the variable with the actual value ,so your code is the same as this:
public static void DoSomething(int value = 2)
Constant variables are replaced at compile-time, so they never really exist in the produced assembly. So code using a constant is really identical to just using the constant value directly. The benefit is just that you can reuse the constant elsewhere and only need to change it in one location.
Now, since constants are always replaced at compile-time, the effect of making them public or private is also quite simple: It just affects what other type can access it at compile-time. So using a private constant for example can be helpful if you just want to keep that constant to the current type, whereas a public constant can be used across the whole application.

Ambiguity in initialization order of static variables

During my research into the best way to build a Singleton in C# I stumbled across the following article where there is a brief mention that in C++
"The C++ specification left some ambiguity around the initialization
order of static variables."
I ended up looking into the question and found this and this. Where basically the point (as far as I understand) is that the initialization order of static variables in C++ is undefined. Ok I guess so far so good, but then I wanted to understand the following statement that the article later makes
"Fortunately, the .NET Framework resolves this ambiguity through its
handling of variable initialization."
So I found this page where they say
The static field variable initializers of a class correspond to a
sequence of assignments that are executed in the textual order in
which they appear in the class declaration.
and give the example of
using System;
class Test
{
static void Main() {
Console.WriteLine("{0} {1}", B.Y, A.X);
}
public static int F(string s) {
Console.WriteLine(s);
return 1;
}
}
class A
{
static A() {}
public static int X = Test.F("Init A");
}
class B
{
static B() {}
public static int Y = Test.F("Init B");
}
the output must be:
Init B
Init A
1 1
"Because the rules for when static constructors execute (as defined in
Section 10.11) provide that B's static constructor (and hence B's
static field initializers) must run before A's static constructor and
field initializers."
But where I am confused is that my understanding was that the initialization order of static variables in these examples would be based on when a method or field within the class was first invoked, which is in turn based on the execution order of the block of code (this case left to right). IE: Completely independent of where - or the order - of the class declaration. Yet by my interpretation of that article it says its as a result of the order of declaration of those classes, which my testing doesn't back up?
Could someone please clarify this (and the point the article is trying to make) for me and perhaps provide a better example that illiterates the behaviour described?
The static field variable initializers of a class correspond to a
sequence of assignments that are executed in the textual order in
which they appear in the class declaration.
This means that within the same class, static fields are initialized in order of appearance in the source code. For example:
class A
{
public static int X = Test.F("Init A.X");
public static int Y = Test.F("Init A.Y");
}
When it's time for the static fields to be initialized, X is guaranteed to be initialized before Y.
"Because the rules for when static constructors execute (as defined in
Section 10.11) provide that B's static constructor (and hence B's
static field initializers) must run before A's static constructor and
field initializers."
This means that the static constructor and member initialization for each class will run in evaluation order when expressions that access these classes appear¹. The relative order of appearance of the class definitions in source code does not play any role, even if they appear in the same source file (which they most certainly are not obliged to do). For example:
static void Main() {
Console.WriteLine("{0} {1}", B.Y, A.X);
}
Assuming that neither A nor B has already been statically initialized, order of evaluation guarantees that all the fields of B will be initialized before any field of A. The fields of each class will be initialized in the order specified by the first rule.
¹ for the purposes of this discussion I am ignoring the existence of beforefieldinit.
In C++ the order of initialization of variables with static storage duration in a single translation unit is the order in which the definitions of such variables occur. It is unspecified what the order of initialization of variables with static storage duration is across different translation units.
That is, the C++ standard does offer a similar guarantee to what you quoted, substituting the order of declaration in the class for the order of definition in the single translation unit that defines such variables. But that is not the important difference.
While in C++ that is the only guarantee, in C# there is the added guarantee that all static members will be initialized before the first use of the class. This means that, if your program depends on A (consider each type in a different assembly which is the worst case), it will start the initialization of all static fields in A, if A in turn depends on B for any of those static initializations, then the initialization of B static members will be triggered there.
Contrast that with C++, where during static initialization[*], all other variables with static duration are assumed to be initialized. This is the main difference: C++ assumes that they are initialized, C# ensures that they are before that use.
[*] Technically the case where this is problematic could be dynamic initialization in the standard. Initialization of variables with static storage duration inside a each translation unit is a two step process, where during the first pass static initialization sets the variables to a fixed constant expression, and later in a second pass called dynamic initialization all variables with static storage whose initializer is not a constant expression are initialized.

C# String gone from struct

Ok.. I have a really awkward problem that I believe is related with how C# handles value types vs reference types but I'm just not sure what exactly the bug is.
public partial class LogicSimulationViewerForm : Form
{
private Dictionary<string, PointStruct> pointValues;
private void SearchPoint(string code)
{
ReadDefaultPointValuesResponse result = ddcdao.ReadDefaultPoint(points);
pointValues = new Dictionary<string, PointStruct>();
for (int j = 0; j < result.pointidentifier.Length; j++)
{
if (!pointValues.ContainsKey(result.pointidentifier[j]))
{
PointStruct ps = new PointStruct();
ps.name = "Random String";
ps.pointidentifier = result.pointidentifier[j];
ps.outofservice = result.outofservice[j];
pointValues.Add(result.pointidentifier[j], ps);
...
pointValues is stored as a private field in a class. Now in the same class but in a different function, if I try to do the following:
PointStruct ps = pointValues[s];
MessageBox.Show(ps.name);
MessageBox.Show(ps.pointidentifier);
MessageBox.Show(ps.outofservice);
The ps.pointidentifier and ps.outofservice is displayed correctly but ps.name is always returned as null no matter what I do. How can I fix this issue?
Edit: Upon request, I am adding more code to further illustrate the problem:
public struct PointStruct
{
public string pointidentifier;
public string affect;
public string outofservice;
public string priorityarray;
public string pointtype;
public string alarmstate;
public string correctvalue;
public string presentvalue;
public string name;
public string test;
}
As long as there is no voodoo (explicit field layouts, property indirection, etc), there is absolutely no reason why a field should wipe itself, regardless of whether it is a class or a struct.
If it was a class, we could perhaps put that down to a careless update somewhere else, i.e.
var foo = pointValues[key];
// snip 2000 lines
foo.name = newValue; // which happens to be null
which would of course update the same fundamental object as the one referenced by the dictionary. But that doesn't apply to a struct, since the copies are separate (unless updating directly in an array).
The only way I can see of causing that, given that you state that pointValues.Add(...) is only used in one place, is that you are overwriting it elsewhere via the indexer:
pointValues[key] = newValueWithANullName;
All that said, though; unless you have some very specific reasons, there is very little purpose for PointStruct to be a struct. That looks to me like it should be a class. It is very "fat" for a struct. Also; in most cases, structs should be immutable.
It would be very surprising for a struct stored in a Dictionary to have any of its string fields change to hold anything other than the value they held when the struct was stored in the Dictionary. Is your name actually a literal "Random String", or are you using that literal to represent some other function? Have you confirmed that the function in question is actually working?
Unlike some people here, I very much like mutable structs, despite the limitations in .net's support for them, because they allow the owner of a struct to control who can mutate it. By contrast, if a reference to a mutable class object has ever been exposed to outside code, there's no telling when or by whom it might be altered. The fact that PointStruct is a struct means that there's a 99.44% chance that the field contents of the struct you are retrieving from the Dictionary are the same as the field contents the struct had when it was stored. Add a check to ensure that the Name field is non-null whenever it's stored to the Dictionary and you'll almost certainly find your problem. A much better situation to be in than with a mutable class, where you'd have to inspect outside code to ensure that nothing's altering it.
Addendum
There is one evil thing about mutable structs, which is that if you have any struct members, other than a constructor or property setters, which mutate this, an attempt to use such a member in read-only contexts will generate bogus code but won't generate any compiler diagnostics. Languages and frameworks which properly support value-type semantics require that members which mutate this be tagged as such, and forbid the use of such members in read-only contexts, but unfortunately .net has no such tagging. It simply guesses that constructors and property setters will mutate the underlying struct, while getters and other methods will not. If the `Name field is filled in with a struct method, e.g.
void ComputeName(void)
{
Name = someRandomString();
}
I would strongly suggest that you replace it with a static method:
void ComputeName(ref theStruct)
{
theStruct.Name = someRandomString();
}
If the former function is called on a read-only instance of PointStruct, the compiler will--as noted--compile without complaint but the resulting code won't work. Attempting to pass a read-only instance of PointStruct to the latter, however, will cause a compiler error.

Local constant initialised to null reference

I have read that C# allows local constants to be initialised to the null reference, for example:
const string MyString = null;
Is there any point in doing so however? What possible uses would this have?
My guess is because null is a valid value that can be assigned to reference types and nullable values types.
I can't see any reason to forbid this.
There might be some far off edge cases where this can be useful, for example with multi targeting and conditional compilation. IE you want to define a constant for one platform but define it as null for another due to missing functionality.
Ex, of possible usefull usage:
#IF (SILVELIGHT)
public const string DefaultName = null;
#ELSE
public const string DefaultName = "Win7";
#ENDIF
Indeed, you can initialize local const strings and readonly reference types to null, even though it seems to be redundant since their default value is null anyway.
However, the fact remains that null is a compile-time constant suitable enough to initialize strings and reference types. Therefore, the compiler would have to go out of its way in order to consider, identify and reject this special case, even though it's still perfectly valid from a language standpoint.
The merits of doing that would be disputable, and it probably wouldn't be worth the effort in the first place.
It could be used if you want to write code without keywords, if that strikes your fancy:
const string UninitializedSetting = null;
if (mySetting == UninitializedSetting)
{
Error("mySetting string not initialized");
}
Choosing to name a value (rather than using an in-place magic constant), using const, and setting to null are more or less orthogonal issues, although I agree that the venn diagram might have a very small area of overlap for the three :)
A case that I can think of is when you have as much or more throw-away data than you do code, but you want to ensure the values don't accidentally get changed while writing or maintaining your code. This situation is fairly common in unit tests:
[Test]
public void CtorNullUserName()
{
const string expectedUserName = null;
var user = new User(expectedUserName);
Assert.AreEqual(expectedUserName, user.Name, "Expected user name to be unchanged from ctor");
}
You could arguably structure such code in a plethora of ways that didn't involve assigning null to a const, but this is still a valid option.
This might also be useful to help resolve method overloading issues:
public class Something
{
public void DoSomething(int? value) { Console.WriteLine("int?"); }
public void DoSomething(string value) { Console.WriteLine("string"); }
}
// ...
new Something().DoSomething(null); // This is ambiguous, and won't compile
const string value = null;
new Something().DoSomething(value); // Not ambiguous
If you use constants, for example, for configuration of your application then why not? The null value can represent a valid state - e.g. that a logger is not installed. Also note that when you declare a local constant, you can initialize it to a value given by global constant (which may be a more interesting scenario).
EDIT: Another question is, what are good situations for using const anyway? For configuration, you'd probably want a configuration file and other variables usually change (unless they are immutable, but then readonly is a better fit...)
Besides the situations already pointed out, it may have to do with a quirk of the C# language. The C# Specification 3.0, section 8.5.2 states:
The type and constant-expression of a local constant declaration must follow the same rules as those of a constant member declaration (§10.4).
And within 10.4 reads as follows:
As described in §7.18, a constant-expression is an expression that can be fully evaluated at compile-time. Since the only way to create a non-null value of a reference-type other than string is to apply the new operator, and since the new operator is not permitted in a constant-expression, the only possible value for constants of reference-types other than string is null.

Categories