E. Moffat
E. Moffat

Reputation: 3288

Self assignment in C#

I was looking through some code I wrote a while ago and realized I made an assumption about the assignment operator in C#. Here is the line of code in question (it works as expected):

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

pointsChecked is a List specified as a parameter to a recursive function. It is a default parameter with default value null. What I want to do is initialize it once and then build a collection of points that I have already checked, so it should only be initialized during the first iteration.

My assumption was that C# is guarded against self-assignment in the same way that C++ operator= should provide a guard when overloaded (ie, if(this == &rightHandSide) return *this;). However, I haven't been able to find any resources that explicitly state that this is true for C#.

The closest example I found was this question about the null-coalescing operator, where it appears that the object is assigned back to itself if it is not null. No one said anything about the self-assignment in that example, but I want to be certain that this isn't a bad practice and that there are no negative side effects.

Searching on MSDN I also found that (paraphrasing based on my understanding) the value on the right hand side is copied over to the value on the left hand side and returned. So I am, again, unsure if it is a bad thing to do a self-assignment.

I know I could do the following to be safer:

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

But I would rather understand what is actually happening with self-assignment.

Upvotes: 14

Views: 4870

Answers (1)

usr
usr

Reputation: 171178

Assignment copies the reference to an object, not the object contents. No customizable code runs as part of an assignment to a variable holding an object reference, ever. This is also true for structs.

In C++ assignment is customizable, in C# it is not.

It is safe to assign the same object reference to a variable already holding it:

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

This is as safe as assigning any other value:

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

Note, that no general way exists to clone/copy an object. Any explanation relying on the presence of such a mechanism must be wrong.

Self-assignment is safe because it translates to the following approximate IL instructions:

ldloc someRef
stloc someRef

This has clearly defined semantics. It first loads someRef onto the stack, then stores whatever is on the stack to someRef.

Upvotes: 11

Related Questions