C# : Changing copy of array changes array itself - c#

I have a very basic question in C#. So I have an array of int called m_permutation (property of a class), and in a method of the class I have the following code:
int[] newPermutation = new int[m_permutation.Length];
newPermutation = m_permutation;
newPermutation[0] = 5;
I am confused as to why m_permutation is also changed in this code, and how can I fix it ?
I understand that I can initialize newPermutation via a loop for, to get the same values of m_permutation, and that fixes it. However, can somebody explain why this happens, and what is the best fix ?
Thank you,
Bogdan

There's some good, and some bad, about your expectations for your code.
Let's go through what your code is actually doing:
int[] newPermutation = new int[m_permutation.Length];
This will declare a new variable, newPermutation, to be an array of ints, and then construct a new int array containing m_permutation.Length elements.
So far so good.
The next line, not so much:
newPermutation = m_permutation;
This line will actually replace the reference in your array variable newPermutation to, after the assignment, refer to the same array as m_permutation.
Let's consider what an array variable actually is.
When you do this:
int[] x = new int[5];
Then you're doing a couple of things:
You're declaring a variable, x
You're constructing a new object containing the int array
You're assigning the variable, x to refer to this object
After the 2nd line:
newPermutation = m_permutation;
you're essentially saying this:
OK, you know that array we just constructed? Forget that
Let's now refer to this other array, the one that the variable m_permutation is also referring to.
So when this line executes:
newPermutation[0] = 5;
You're essentially saying: The array that newPermutation is now referring to, its first element should now have the value 5.
Since newPermutation at this point refers to the same array as m_permutation, it appears that you're modifying an additional array but in reality you only have one array. You do, however, have two variables referring to the same array.
I recommend you read my answer here regarding pointers since this is relevant.
However, there is an easy fix to your problem.
You can ask for a copy of the array, instead of a reference to the original one.
Simply change your code to this:
int[] newPermutation = m_permutation.ToArray();
The .ToArray() method is guaranteed to return a new array, so this won't be shared with the original.
Bear in mind, however, that if you do this with anything more complex than an int, such as an object, you're only getting copies of the object references, not the objects themselves. You can get back to Stack Overflow with new questions when/if you get to this point.

Because they both reference the same object in memory.
You can use,
Array.Copy(m_permutation, newPermutation,m_permutation.Length );

Related

How to declare an array of deserialized class parameters without initializing it?

I consider this as a continuation of what I've learned from my two previous threads. Instead of Javascript I will be using pure C#.
I have a class with 3 parameters in it, and I am creating a variable which is a result of deserialization to class type
var param = js.Deserialize<ClassName>(jqData.Params);
Based on what I've learned from my first thread, it stores values based on inputs I've made within 3 textboxes that I have.
For our purposes, let's assume I only placed input in a second textbox out of three, so the values would be null, "abc", null.
Now, I got some very good suggestions from my second post, which I want to implement.
I want to create an array of objects, WITHOUT initializing, since those objects already hold values, reduce array down to 1 element based on criteria from that excellent post, and then proceed with my validation logic.
However, I am struggling with declaring array part. From what I saw here in SO, most of threads are talking about declaring and initializing those elements. I don't need it.
What I need is to declare an array, which would have class elements in it, something like array = [param.elem1, param.elem2, param.elem3], and when I run a code, it will return [null, "abc", null].
Can you please point me in the right direction on how to properly declare such array?
Your idea was close to how this can be handled. Just change your array = [param.elem1, param.elem2, param.elem3] to:
var myArray = new object[] { param.elem1, param.elem2, param.elem3 };
If you know the type of param.elem1/2/3, you can use the specific type (e.g. string[] instead of object[]).

Can you make an element and an element-in-a-list act like the same object?

I know from questions like: "Is it Possible to store references to objects in list?" that you can modify a property on an object without removing the object from a list. So you can make a wrapper class and put your object inside it, then modify the value. However, if what you are trying to do is change the object itself...
What I want to know is: Can you make a series of objects, store them in a list like structure, and then access them from either the list or the objects? Can you make object and the object-in-the-list act like they are the same object? Can you do this if you use an array?
Using System;
Using System.Collections.Generic;
Namespace Project1
{
Class Test
{
Public static void Main()
{
int one = 1;
int two = 2;
int num = 3;
List<int> myList = new List<int>();
myList.Add(one);
myList.Add(two);
myList.Add(num);
myList[2] = 4; // I want this to also set num to 4
num = 5; // I want this to also set myList[2] to 5
Console.WriteLine(myList[2]); //prints 4
Console.WriteLine(num); //prints 5
}
}
}
Looking at your code example, I think I understand what you are getting at. Basically, you want to access the element in the array directly and not by the indexed property accessor. It's very simple to do that, as long as the item in the array is a reference type. However, this won't work with value types, because the standalone variable and the indexed property are pointing to different memory storage spaces when value types are involved.
To illustrate:
listOfPersons[2] = new Person { Name = "Homer Simpson", Age = 35 };
Console.WriteLine(listOfPersons[2].Name); // will show Homer Simpson
Person myself = listOfPersons[2];
myself.Name = "Bart Simpson";
Console.WriteLine(myself.Name); // will show Bart Simpson
Console.WriteLine(listOfPersons[2].Name); // will show Bart Simpson
Console.WriteLine(listOfPersons[2].ReferenceEquals(myself)); // will show true
On the other hand:
listOfInts[2] = 2;
Console.WriteLine(listOfInts[2]); // will show 2
int myInt = listOfInts[2];
myInt = 5;
Console.WriteLine(myInt); // will show 5
Console.WriteLine(listOfInts[2]); // will show 2...
Hope this helps!
First, your code doesn't have any objects except the List object you created. Integers are not objects. You could box the integers, but C# will copy on both boxing and unboxing so you couldn't use that for what you are asking.
In general, to get the behavior you're looking for, you need to use a reference type (i.e. an object) that exposes a property of the type you want to use. Note, however, even for reference types, you can absolutely have two references that refer to the same object, but the references themselves are distinct - so changing one reference to refer to a different object won't change what the other reference is referring to.
You can pass parameters by reference to a method or function call, but you can't store this reference (not even by trying to close over it with a lambda), so you can't keep a reference in a list and use it to update the variable that was added to the list.
You could mock up a very cludgy workaround where you maintained a list of Func<T>/Action<T> getter/setter pairs and use lambdas to close over the original variable before you add it to the collection, but if you're going to that level, you are long past the point where you should take a step back and figure out why you're taking the path of most resistance.
Simply put, this isn't the kind of thing you really should find yourself needing to do - and if it's something you encounter, it might be a sign you've missed another, better way to architect your code.

Replace object but keep previous memory location in c#

Let's say I have a list:
List<object> list = new List();
list.Add(object1);
list.Add(object2);
object foo = list[0];
How do I make a call to list to replace list[0] such that foo will automatically point to the newly replaced object?
I know this line won't do the trick as foo will continue pointing to the old value of list[0]...
list[0] = object3;
Thanks!
It's not possible in my opinion. You need an additonal level of indirection which you have to implement yourself.
You could use a delegate/ anonymous lambda that fetches list[0]:
Func<object> foo = () => list[0];
Of course that changes the syntax slightly since it's now foo() instead of foo but it has the effect that you can fetch the value of list[0] at any time later and it always gets the current value.
What you really want to be able to do is to override the assignment operator but that's not possible in C#. The closest you'll get is to create a class that behaves a bit like Nullable<T> having a .Value property on it and assign to that .Value property instead of overwriting the object itself in the list.
You can use the fixed keyword but only in unsafe code. But i'm not sure what your attempting to do so it may not suite your needs if you need this level of control c++ cli would be a better choice.
Unsafe pointers are one possibility: http://msdn.microsoft.com/en-us/library/y31yhkeb(v=vs.80).aspx
For "safe" code, you can do something like store your value in an array of length 1, and then only store references to the array and always access the value by array[0], but this is a bit of a hack and there is probably a better way to do what you want to accomplish.

Does Array.ToArray<>() return the original array if it is the same type?

I deal with a framework on a daily basis where we sometimes provide methods that accept IEnumerable<MyBusinessObject> as a parameter in order to show user interfaces, perform calculations etc.
If I pass in an array of MyBusinessObject like so:
MyBusinessObject[] myArray = new MyBusinessObject { obj1, obj2, ..., objN };
frameworkClass.MyMethod(myArray);
....
public class FrameworkClass
{
public void MyMethod(IEnumerable<MyBusinessObject> objs)
{
// Other code that uses the enumerable
MyBusinessObject[] objectArray = objs.ToArray();
// More code that uses the enumerable
}
}
Does the line objs.ToArray() simply resolve the IEnumerable<MyBusinessObject> back to the original array, or does it copy it to a whole new array, ready for use?
No, you will always get a new copy of the array, though the objects in it aren't copies, they are the same references as in the original array.
It would be very inconsistent for changes to the returned array to sometimes affect the source and sometimes not. ToList works the same way for the same reason.
You can check source code (as of 2015) if you need to review details: Enumerable.ToArray which in turn creates copy of elements (optimized for ICollection and hence Array[], but still making copy) with internal Buffer class.
You will get a new copy of the array if there is one or more element in it. For empty arrays, you might get the same array back, at least in .NET 5:
Console.WriteLine(Object.ReferenceEquals(Array.Empty<string>(), Array.Empty<string>().ToArray()));
This returns true.

Direct array initialization with a constant value

Whenever you allocate a new array in C# with
new T[length]
the array entries are set to the default of T. That is null for the case that T is a reference type or the result of the default constructor of T, if T is a value type.
In my case i want to initialize an Int32 array with the value -1:
var myArray = new int[100];
for (int i=0; i<myArray.Length; i++) { myArray[i] = -1; }
So after the memory is reserved for the array, the CLR loops over the newly allocated memory and sets all entries to default(int) = 0. After that, my code sets all entries to -1.
That makes the initialization redundant. Does the JIT detect this and neglects the initialization to 0 and if not, is there a way to directly initialize a portion of memory with a custom value?
Referring to C# Array initialization - with non-default value , using Enumerable.Repeat(value, length).ToArray() is no option, because Enumerable.ToArray allocates a new array and copies the values to it afterwards.
Similar to Dan's answer but without the need of using collections:
int[] myArray = Enumerable.Repeat(-1, 100).ToArray();
It's not redundant.
Suppose an exception is thrown during your initialization loop. If the CLR hasn't cleared the memory first, you might be able to "see" the original uninitialized memory, which is a very bad idea, particularly from a security standpoint. That's why the CLR guarantees that any newly allocated memory is wiped to a 0 bit pattern.
The same argument holds for fields in an object, by the way.
I suppose in both cases the CLR could check that you're not going to make the array visible elsewhere before finishing initialization, but it's a complicated check to avoid a pretty simple "wipe this area of memory".
If you buy into Arrays considered somewhat harmful, then your question would be moot as you would write:
var myArray = new List<int>(Enumerable.Repeat(-1, 100));
I highly doubt that the JIT will optimize away the default set for this scenario. The reason being is that this would be an observable difference. Consider the following slightly altered scenario.
obj.myArray = new int[100];
for (int i=0; i<myArray.Length; i++) { obj.myArray[i] = -1; }
It's entirely possible for the loop to throw. At least, it's probably not possible for the JIT to prove it doesn't. If it did throw and the CLR did not default initialize the memory, the result would be observable if you still had a reference to obj.
I suggest using Array.Fill as a very succint way to fill an array with an initial value:
bool[] isPrime = new bool[MaxNum];
Array.Fill(isPrime, true);
This initializes all values in the isPrime array to true.
If you are looking for one liner solution then you could use below:
var myArray = Array.ConvertAll(new int[100], i => -1);

Categories