13

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

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

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

我的假设是 C# 可以防止自赋值,就像 C++在重载时operator= 应该提供保护一样(即if(this == &rightHandSide) return *this;)。但是,我无法找到任何明确声明这适用于 C# 的资源。

我发现的最接近的例子是这个关于 null-coalescing operator 的问题,如果不是,则似乎对象被分配回自身null。没有人对那个例子中的自我分配说任何话,但我想确定这不是一个坏习惯,并且没有负面影响。

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

我知道我可以执行以下操作以更安全:

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

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

4

1 回答 1

11

赋值复制对对象的引用,而不是对象内容。从来没有可定制的代码作为分配给包含对象引用的变量的一部分运行。这也适用于结构。

在 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.

于 2013-09-15T18:29:38.480 回答