Reputation: 23
Consider class A
with private field _data
of any type (eg. int
) and property Data
to work with that field:
public class A
{
private int _data;
public int Data
{
get => _data;
set => _data = value;
}
// Constructor is redudant, I created that for testing purposes...
public A(int data)
{
_data = data;
}
}
Now consider class B
with the same private field _data
and property Data
that only returns reference to our field:
public class B
{
private int _data;
public ref int Data
{
get => ref _data;
}
// Constructor is redudant, I created that for testing purposes...
public B(int data)
{
_data = data;
}
}
And now the question for which I can't find the answer: Why I'm able to change the value of _data
in the instance of class B
if there is no set
modifier for Data
?
B b = new B(50);
// This line doesn't produce any warnings or errors
b.Data = 100;
Console.WriteLine(b.Data == 100); // True
Does that work like pointers in C/C++ and compiler understands that this property is just a pointer, so it automatically assings value to what this pointer point to (without any special operators and/or casting) or I'm missing something?
I couldn't find an answer on this on learn.microsoft.com
(searching both for Properties
and ref
), so any explanation would be appreciated.
Upvotes: 2
Views: 128
Reputation:
Indeed, using ref we get a reference and we can change the value.
Considering this code:
A a = new A();
B b = new B();
a.Data = 100;
b.Data = 200;
The IL generated code is:
// A a = new A();
IL_0001: newobj instance void ConsoleApp.A::.ctor()
IL_0006: stloc.0
// B b = new B();
IL_0007: newobj instance void ConsoleApp.B::.ctor()
IL_000c: stloc.1
// a.Data = 100;
IL_000d: ldloc.0
IL_000e: ldc.i4.s 100
IL_0010: callvirt instance void ConsoleApp.A::set_Data(int32)
// b.Data = 200;
IL_0016: ldloc.1
IL_0017: callvirt instance int32& ConsoleApp.B::get_Data()
IL_001c: ldc.i4 200
IL_0021: stind.i4
Using the setter, we call a method, and pass the int32 value
as a parameter.
Using the by ref getter, we got the reference, to an integer here : int32&
.
Properties having a getter by ref can't have a setter, says the compiler.
Because it is useless and redundant.
Thus, a treatment can only be done in a by ref getter, for example to return one or the other reference according to certain conditions:
CurrentColor
of a control that isEnabled
will returnsColorEnabled
, elseColorDisabled
.
The native x86 machine code transcribed for a.Data = 100
is:
mov rcx,qword ptr [rbp+40h]
mov edx,64h
cmp dword ptr [rcx],ecx
call 00007FF7E93B0568
For b.Data = 200
is:
mov rcx,qword ptr [rbp+38h]
cmp dword ptr [rcx],ecx
call 00007FF7E93B0580
mov qword ptr [rbp+20h],rax
mov rax,qword ptr [rbp+20h]
mov dword ptr [rax],0C8h
Upvotes: 4