赋值运算符 =
将其右操作数的值赋给变量、属性或由其左操作数给出的索引器元素。 赋值表达式的结果是分配给左操作数的值。 右操作数类型必须与左操作数类型相同,或可隐式转换为左操作数的类型。
赋值运算符 =
为右联运算符,即形式的表达式
a = b = c
计算结果为
a = (b = c)
以下示例演示使用局部变量、属性和索引器元素作为其左操作数的赋值运算符的用法:
List<double> numbers = [1.0, 2.0, 3.0];
Console.WriteLine(numbers.Capacity);
numbers.Capacity = 100;
Console.WriteLine(numbers.Capacity);
// Output:
// 4
// 100
int newFirstElement;
double originalFirstElement = numbers[0];
newFirstElement = 5;
numbers[0] = newFirstElement;
Console.WriteLine(originalFirstElement);
Console.WriteLine(numbers[0]);
// Output:
// 1
// 5
赋值操作的左操作数接收右操作数的值。 当操作数是值类型时,赋值操作将复制右侧操作数的内容。 当操作数为引用类型时,赋值操作会复制对对象的引用。
此操作叫做赋值:赋予值。
从 C# 14 开始,赋值的左侧可以包含 null 条件成员表达式,例如 ?.
或 ?[]
。 如果左侧为空,则不会计算右侧表达式。
ref 赋值
如果 Ref 赋值= ref
,则其左侧操作数成为右侧操作数的别名,如以下示例所示:
void Display(double[] s) => Console.WriteLine(string.Join(" ", s));
double[] arr = { 0.0, 0.0, 0.0 };
Display(arr);
ref double arrayElement = ref arr[0];
arrayElement = 3.0;
Display(arr);
arrayElement = ref arr[arr.Length - 1];
arrayElement = 5.0;
Display(arr);
// Output:
// 0 0 0
// 3 0 0
// 3 0 5
在前面的示例中,局部引用变量arrayElement
初始化为第一个数组元素的别名。 然后,向其重新赋值 ref
,以引用最后一个数组元素。 因为它是别名,所以使用普通赋值运算符 =
更新其值时,也会更新相应的数组元素。
ref
赋值的左侧操作数可以是局部引用变量、ref
字段和 ref
、out
或 in
方法参数。 两个操作数的类型必须相同。
ref
赋值意味着引用变量具有其他引用对象。 它不再引用其先前的引用对象。 对 ref
参数使用 ref =
意味着该参数不再引用其参数。 在 ref 重新赋值之后修改对象状态的任何操作都会对新项目进行这些修改。 例如,考虑使用以下方法:
private static void RefReassignAndModify(scoped ref string s)
{
string sLocal = "Hello";
Console.WriteLine(sLocal); // Output: Hello
s = ref sLocal;
s = "World";
Console.WriteLine(s); // Output: World
以下用法表明,在进行方法调用之后对参数 s
的赋值不可见,因为在修改字符串之前,已对 s
进行了 ref
重新赋值以引用 sLocal
:
string msg = "Hi";
RefReassignAndModify(ref msg);
Console.WriteLine(msg); // Output: Hi!
复合赋值
对于二元运算符 op
,窗体的复合赋值表达式
x op= y
等效于
x = x op y
不过 x
只评估一次。
Null 合并赋值
只有在左操作数计算为 null
时,才能使用 null 合并赋值运算符 ??=
将其右操作数的值分配给左操作数。 有关详细信息,请参阅 ??
和 ??=
运算符一文。
运算符可重载性
用户定义类型不能重载赋值运算符。 但是,用户定义类型可以定义到其他类型的隐式转换。 这样,可以将用户定义类型的值分配给其他类型的变量、属性或索引器元素。 有关详细信息,请参阅用户定义转换运算符。
用户定义类型不能显式重载复合赋值运算符。 但是,如果用户定义类型重载了二元运算符 op
,则 op=
运算符(如果存在)也将被隐式重载。