why readonly field whose type is struct generates ldloca instead of ldflda ? #94145
-
A have a struct type struct Core
{
public Core() => i = 0;
public int i;
public void Inc() { i++; }
} that is a class Foo
{
public Foo()
{
j = 0;
core = new Core();
}
public int j;
public int i => core.i;
public readonly Core core;
public void Inc()
{
j++;
core.Inc();
}
} whoever when I ran the following code the result was different of the expected var main = new Foo();
Do();
Do();
Do();
void Do()
{
main.Inc();
Console.WriteLine(main.i);
Console.WriteLine(main.j);
} produces 0
1
0
2
0
3 instead of 1
1
2
2
3
3 I notice that problem is resolved wether
analysing the IL code I notice that when it is a
to find the value of a field, load its content and assign it to a local variable it declates by itself, thus making a copy of the field in its initial state (voilà!) and use the copy, so the field value is keeped untouchable each time the method if I remove the
to find the address of a field and use it, therefore the field has its state changed through the method calls. ok, thats answer how the program is producing this ouput. the question now is why? why the C# compiler makes a defensive copy when the field is As final test to check if it could be some IL limitation, I ran IL directly keeping both |
Beta Was this translation helpful? Give feedback.
Replies: 2 comments 3 replies
-
You are reassigning the field, though.
You don't have a |
Beta Was this translation helpful? Give feedback.
-
Well, you have to remember that having a field marked read-only means that this piece of memory that this field occupies shouldn't be mutated by conventional means. For class read-only fields this obviously means that a reference/pointer to the heap shouldn't be mutated/changed. For struct read-only field this means that whatever fields you have on a struct, they become literally a part of your class body and they can't be mutated. It works for a class fields because when you call a mutating method you know it will change the class body on the heap but not a read-only reference to it (you can see it as a read-only struct that contains a reference/pointer, actually). For struct fields compiler has to make a defensive copy because you're calling a mutating method on read-only value itself |
Beta Was this translation helpful? Give feedback.
On the stack isn't important here. The important bit is that the actual value of the struct is saved into the field itself. This is why I said "but you are reassigning the field" - the act of mutation would modify the field.
Since you disallowed that (since you added
readonly
to the field, the only way for the compiler to enforce this with a mutable struct is to take the defensive copy.