C# 中的自赋值

本文关键字:赋值 | 更新日期: 2023-09-27 18:31:26

我正在查看我不久前编写的一些代码,并意识到我对 C# 中的赋值运算符做出了假设。这是有问题的代码行(它按预期工作):

pointsChecked = pointsChecked ?? new List<Point>();

pointsChecked 是指定为递归函数参数的列表。它是默认值为 null 的默认参数。我想做的是初始化它一次,然后构建我已经检查过的点的集合,所以它应该只在第一次迭代期间初始化。

我的假设是,C# 受到保护,其方式与C++ operator=在重载(即 if(this == &rightHandSide) return *this; )时应该提供保护的方式相同。但是,我找不到任何明确声明 C# 适用于

此的资源。

我发现的最接近的例子是关于空合并运算符的问题,如果对象不null,则对象似乎被赋回自身。在这个例子中,没有人说任何关于自我分配的事情,但我想确定这不是一个坏做法,也没有负面的副作用。

在 MSDN 上搜索时,我还发现(根据我的理解进行释义)右侧的值被复制到左侧的值并返回。所以我再次不确定做自我分配是否是一件坏事。

我知道我可以做以下事情来更安全:

if(pointsChecked == null)
{
    pointsChecked = new List<Point>();
}

但我宁愿了解自我分配的实际情况。

C# 中的自赋值

赋值复制对对象的引用,而不是对象内容。从来没有可自定义的代码作为保存对象引用的变量赋值的一部分运行。对于结构也是如此。

在C++赋值是可自定义的,而在 C# 中则不是。

将相同的对象引用分配给已经持有它的变量是安全的:

object someRef = new object();
someRef = someRef; //always does nothing

这与分配任何其他值一样安全:

int someVal = 123;
someVal = someVal; //always does nothing

请注意,没有通用的方法来克隆/复制对象。任何依赖这种机制存在的解释都一定是错误的。

自分配是安全的,因为它转换为以下近似的 IL 指令:

ldloc someRef
stloc someRef

这已经明确定义了语义。它首先将someRef加载到堆栈上,然后将堆栈上的任何内容存储到someRef