属性和参考
Properties and ref
考虑 class A
与任何类型的私有字段 _data
(例如 int
)和 属性 Data
一起工作该字段:
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;
}
}
现在考虑 class B
具有相同的私有字段 _data
和 属性 Data
只有 returns 引用我们的字段:
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;
}
}
现在我找不到答案的问题是:为什么我能够在 class B
的实例中更改 _data
的值,如果有的话Data
没有 set
修饰符?
B b = new B(50);
// This line doesn't produce any warnings or errors
b.Data = 100;
Console.WriteLine(b.Data == 100); // True
它是否像 C/C++ 中的 pointers 一样工作并且编译器理解这个 属性 只是一个 pointer,所以它会自动为这个指针指向的值赋值(没有任何特殊运算符 and/or 转换)或者我遗漏了什么?
我在 docs.microsoft.com
(同时搜索 Properties
和 ref
)上找不到关于此问题的答案,因此不胜感激。
确实,使用 ref 我们可以获得一个引用,我们可以更改值。
考虑这段代码:
A a = new A();
B b = new B();
a.Data = 100;
b.Data = 200;
IL 生成的代码是:
// 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
使用setter,我们调用一个方法,并将int32 value
作为参数传递。
使用 by ref getter,我们在这里得到了一个整数的引用:int32&
.
编译器说,通过 ref 具有 getter 的属性不能具有 setter。
因为没有用而且多余
因此,只能通过参考 getter 进行处理,例如根据特定条件 return 一个或另一个参考:
CurrentColor
of a control that is Enabled
will returns ColorEnabled
, else ColorDisabled
.
为 a.Data = 100
转录的本机 x86 机器码是:
mov rcx,qword ptr [rbp+40h]
mov edx,64h
cmp dword ptr [rcx],ecx
call 00007FF7E93B0568
对于b.Data = 200
是:
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
考虑 class A
与任何类型的私有字段 _data
(例如 int
)和 属性 Data
一起工作该字段:
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;
}
}
现在考虑 class B
具有相同的私有字段 _data
和 属性 Data
只有 returns 引用我们的字段:
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;
}
}
现在我找不到答案的问题是:为什么我能够在 class B
的实例中更改 _data
的值,如果有的话Data
没有 set
修饰符?
B b = new B(50);
// This line doesn't produce any warnings or errors
b.Data = 100;
Console.WriteLine(b.Data == 100); // True
它是否像 C/C++ 中的 pointers 一样工作并且编译器理解这个 属性 只是一个 pointer,所以它会自动为这个指针指向的值赋值(没有任何特殊运算符 and/or 转换)或者我遗漏了什么?
我在 docs.microsoft.com
(同时搜索 Properties
和 ref
)上找不到关于此问题的答案,因此不胜感激。
确实,使用 ref 我们可以获得一个引用,我们可以更改值。
考虑这段代码:
A a = new A();
B b = new B();
a.Data = 100;
b.Data = 200;
IL 生成的代码是:
// 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
使用setter,我们调用一个方法,并将
int32 value
作为参数传递。使用 by ref getter,我们在这里得到了一个整数的引用:
int32&
.
编译器说,通过 ref 具有 getter 的属性不能具有 setter。
因为没有用而且多余
因此,只能通过参考 getter 进行处理,例如根据特定条件 return 一个或另一个参考:
CurrentColor
of a control that isEnabled
will returnsColorEnabled
, elseColorDisabled
.
为 a.Data = 100
转录的本机 x86 机器码是:
mov rcx,qword ptr [rbp+40h]
mov edx,64h
cmp dword ptr [rcx],ecx
call 00007FF7E93B0568
对于b.Data = 200
是:
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