Reference type vs value type

Classes and objects are reference types and when we assign them to a new object, we are just assigning the reference, not the actual object. And this is valid for C#, JavaScript, LINQ, the map function of es6 and everywhere.

They only return new values if it is a value type like primitive types like integers or structs. but if we are returning objects it always returns the reference and if we change the object properties it'll change in the source object as well. Unless we create a new object by using the new keyword in the c# or we use the spread function in JavaScript ({...obj}). It is important to understand that speared only works with one level and with primitive types so if the object has another object in it then that object would be copied by reference and changing that object will change the source object too.

To understand it a bit better consider the following code:

var item1 = new Item(1);
var item2 = new Item(2);

var temp = item1;
item1 = item2;

Let's assume that item1 is pointing to location 1000 in memory, and item2 is pointing to location 2000 in memory. In line 3 when we assign item1 to temp, we basically point the temp object to the location that item1 is pointing. So now temp is pointing to location 1000 in memory and that's it. Any further changes to item1 have nothing to do with temp hence when in line 4 when we change the pointer of item1 from 1000 to 2000 it only changes the item1 pointer and does nothing to the temp object. You can consider this kind of assignment as a snapshot of the references at the assignment line. Since in line 3, item1 was pointing to 1000, temp is pointing to 1000 and what happens after that doesn't affect temp unless we assign temp to item1 again to point it to the new location (2000).

Don't mutate objects in LINQ Select function and always return a new object. LINQ Select is exactly like the JavaScript map function. You need to create a new object if you don't want to mutate your source object. If the object is complicated you can deep copy it or add an interface like ICopy which implements a method for returning a copy of the object this is more efficient than a deep copy because in a deep copy compiler has no idea about the properties at compile time and it uses reflection but if we implement ICopy it gets compiled and it gets the benefits of optimisations that compiler does in compile time.