The following code is illegal:
public struct MyStruct
{
public MyStruct(int a, int b)
{
this.a = a;
this.b = b;
}
public int a;
public int b;
}
//now I want to cache for whatever reason the default value of MyStruct
MyStruct defaultValue;
...
if (foo != defaultValue) //use of unassigned variable...
The way things should be done is obviously:
MyStruct defaultValue = default(MyStruct) //or new MyStruct();
...
if (foo != defaultValue) //compiler is happy
But the following is also allowed (I didn't know this and stumbled upon it by accident):
MyStruct defaultValue;
defaultValue.a = 0;
defaultValue.b = 0;
...
if (foo != defaultValue) //legal
I guess the compiler verifies that all fields of the struct
have been initialized and therefore allows this code to compile. Still I find it confusing with how the rest of the language works. After all, you are basically using an unassigned variable in the C# way of seeing things.
Things get even more confusing if you consider the following code:
public struct MyStruct
{
public MyStruct(int a, int b)
{
this.a = a;
this.b = b;
this.c = (a + b).ToString();
}
public int a;
public int b;
internal string c;
}
The following code is illegal becuase in this case we haven't assigned all visible fields:
MyStruct defaultValue;
defaultValue.a = 0;
defaultValue.b = 0;
...
if (foo != defaultValue) //use of unassigned variable...
Visible is the key word here, because if MyStruct
were to be defined in a referenced assembly then c
is not visible and the compiler will not complain and the previous code would be perfectly valid. Confusing again.
Can somebdoy please explain why its allowed to initialize a struct
in C# in such manner? Why not disallow it completely so there is a more unified experience when dealing with any type of value in the language?
EDIT 1: I made a mistake in the last example. The compiler will be happy only if the not visible field is of reference type. Even more confusing. Is this last case a known bug in the compiler or is there a sane reason for it to work the way it does?
Changed last example to a valid case.
EDIT 2: I'm still a litte befuddled with how value-type initialization works. Why isn't the following allowed for instance:
struct MyStruct
{
public int A { get; set; } //Auto-implemented property
public int B { get; set; } //Auto-implemented property
}
MyStruct defaultValue;
defaultValue.A = 0; //use of unassigned variable...
defaultValue.B = 0;
The way I see it, there is little doubt that all fields MyStruct
are initialized. I can see the reasoning of why this wouldn't be allowed if properties were not auto-implemented as it is arguably possible that the setters do not garantee that all fields are set. But in auto-implemented properties the compiler knows with 100% certainty that the fields will be set if the properties are (after all its code that the compiler generates for you).
Finally, a small theoretical case with evidently no practical use:
struct MyUselessStruct
{
}
MyUselessStruct defaultValue;
Console.WriteLine(defaultValue.ToString()); //hehe did I get away with using an unassigned variable?
Then why isn't this allowed:
Object object;
if (object == null) .... //use of unassigned variable
I find both cases similar in concept and I'd expect them both to work the same way in C#. I still don't understand why this seemingly useless differentiation in the way value-type variables can be initialized and what is it's practical use (on top of the inconsistencies I explained in the first part of my question)
The spec explicitly allows this; 12.3 in ECMA334v4
- A struct-type variable is considered definitely assigned if each of its instance variables is considered definitely assigned.
However, mutable structs are evil. So I strongly suggest you DO NOT do this.
Make the fields private readonly, set them via a custom constructor, and access them via a get
-only property:
public struct MyStruct
{
public MyStruct(int a, int b)
{
this.a = a;
this.b = b;
}
public int A { get { return a; } }
public int B { get { return b; } }
private readonly int a, b;
internal int C { get { return a + b; } }
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With