我正在看一下我之前写过的一些代码,并意识到我对C#中的赋值运算符做了一个假设.以下是有问题的代码行(它的工作原理如下):
pointsChecked = pointsChecked ?? new List<Point>();
pointsChecked是一个指定为递归函数参数的列表.它是默认值为null的默认参数.我想做的是初始化一次,然后构建一个我已经检查的点的集合,所以它只应该在第一次迭代中被初始化.
我的假设是C#被保护不要自我分配,就像C运算符=在重载时应该提供一个警戒(即if(this ==& rightHandSide)return * this;)).但是,我没有找到任何明确声明这对C#是正确的资源.
我找到的最接近的例子是this question about the null-coalescing operator,如果对象不是null,那么对象被分配回自身.在这个例子中,没有人说过自我分配,但是我想确定这不是一个糟糕的做法,没有任何负面的影响.
Searching on MSDN我也发现(根据我的理解改写)右边的价值被复制到左边的价值并返回.所以我再一次不确定自己做一个不好的事情.
我知道我可以做以下更安全的事情:
if(pointsChecked == null) { pointsChecked = new List<Point>(); }
但是我宁愿明白自我分配的实际情况.
解决方法
赋值将引用复制到对象,而不是对象内容.永远不会有可定制的代码作为赋值给持有对象引用的变量的一部分运行.结构也是如此.
在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.