I have problem when using static variable in my project (force using static variable)
public static List<int> a = new List<int>();
public static List<List<int>> list = new List<List<int>>();
public Form1()
{
for (int i = 0; i < 5;i++ )
a.Add(i);
list.Add(a);
Console.WriteLine(list[0].Count); // **count = 5**
a.RemoveAt(0);
list.Add(a);
Console.WriteLine(list[0].Count); // **count = 4**
Console.WriteLine(list[1].Count); // count = 4
}
When I use a.RemoveAt(0) , it makes list[0] change. Why does it do this and how can I fix it?
Well yeah, you're referring to the same object because List<T> is a reference type. See: http://msdn.microsoft.com/en-us/library/s6938f28.aspx
For example:
List<int> a = new List<int>();
List<int> b = a;
Console.WriteLine(Object.ReferenceEquals(a, b)); //true
a.Add(1);
Console.WriteLine(a[0]); //1
Console.WriteLine(b[0]); //1
a[0] = 9000;
Console.WriteLine(a[0]); //9000
Console.WriteLine(b[0]); //9000
Storing a list in a list will yield the same result: you are pointing to the same original list.
If you want to store a copy of a in list[0], then make a copy:
list.Add(new List<int>(a));
Or use linq to make it more succinct:
list.Add(a.ToList());
(make sure to add a using System.Linq; directive to the top of your code file)
You must understand it from basics. Lists objects work through reference. When you added object a to list, that means you added a reference of a to list. Now what ever you change in a that will be reflected in list[0] also as it is referring to same reference.
To achieve this, you can do some like this.
var masterList = new List<List<int>>();
var l1 = new List<int>{1, 2, 3, 4, 5}; // Reference created for l1
var l2 = new List<int>(); // Reference created for l2
masterList.Add(l1); // l1 reference added to masterList
masterList.Add(l2); // l2 reference added to masterList
l2.AddRange(l1); // This will copy values from l1 reference to l2 reference and will not touch the references
l2.RemoveAt(0); // First value removed from reference l2 (And therefore it should not affect reference l1)
MessageBox.Show(masterList[0].Count.ToString() + " and " + masterList[1].Count.ToString());
It must help you to understand whats happening here. You must also remember that it has NOTHING to do with static variables as your question heading indicates.
Hope it helps.
list is keeping a reference to a so if you change the object a then the count in list will also change because it refers to the same thing.
What you need to do is make a copy of a and pass that into list, allowing list to keep a separate reference to a and allowing you to keep the count the same.
Example:
list.Add(a.ToList()); // See Chris Sinclair's example, full credit to him
you need to make copy of list(because list is keep+ing a reference to a):
public static List<int> a = new List<int>();
public static List<List<int>> list = new List<List<int>>();
for (int i = 0; i < 5; i++)
a.Add(i);
list.Add(a.Select(i => i).ToList());//passed in a copy of a.
Console.WriteLine(list[0].Count); // **count = 5**
a.RemoveAt(0);
list.Add(a);
Console.WriteLine(list[0].Count); // **count = 5**
Console.WriteLine(list[1].Count); // count = 4
Related
I cannot find an answer because it seems too much specific. So here's my issue with C#.
We can add another list to another one as a clone like this
list2 = new List<int>(list1);
What I want to know is how can I add a List into another one without any reference of the child?
List<List<List<int>>> wireCoords = new List<List<List<int>>>();
List<int> coord = new List<int>();
for(int i = 0; i < inputSplits.Length; i++)
{
coord.Add(0);
coord.Add(0);
wireCoords[i].Add(coord);
}
AS soon the wireCoords[0][0] list change, it also change inside wireCoords[1][0]
How can I fix this?
Two things. You cannot access a List via [i] accessor unless it has content at that index. Second, you can copy the values of a list by using List1.AddRange(List2). After this, changing List2 will not change List1.
In your for loop, the number of items grow to inputSplits.Length * 2 for every index of wiredCoords. To explain why this happens, lets take an example.
List<int> object1 = new List<int>();
object1.Add(1);
object1.Add(2);
List<int> object2 = object1;
object1.Add(3);
// at this time, object2 also has an element 3.
Console.WriteLine(string.Join(",", object2));
output:
1,2,3 (instead of 1,2 that you'd normally expect)
object1 never gets assigned the "value" of object2. object1 will get "reference" of the object2 and anywhere in code when you change values of object1, object2 will automatically get updated.
Fix for that could be
List<int> object2 = object1;
object1 = new List<int>(); // re-initialized
object1.Add(3);
// object1 has only 1 element
// object2 has 2 elements.
To resolve this, you create a new object or re-initialize the object to get a new reference and then use that for later assignments.
Your code:
List<List<List<int>>> wireCoords = new List<List<List<int>>>();
List<int> coord ;
for(int i = 0; i < inputSplits.Length; i++)
{
coord = new List<int>();
coord.Add(0);
coord.Add(0);
wireCoords.Add(coord);
}
Hope it helps.
Adding to extensive explanation of the issue by #Jawad, here is how you can do that with LINQ in more concise and functional way:
List<List<List<int>>> wireCoords = inputSplits
.Select(_=> new List<int>(){0,0})
.Select(coords=> new List<List<int>>(){coords})
.ToList();
I'm trying to populate fields in one list with values from another list. I'm having trouble figuring out how to avoid the Argument Out of Range exception in the new List. I tried initializing the size of the new list to myObjectA.Count but then read that this won't actually initialize the list of that size like an array would. I'm a little stuck and was hoping for some assistance. Thanks
List<objectA> myObjectA =_GetList(id);
List<objectB> myObjectB = new List<objectB>();
for (var i=0; i < myObjectA.Count; i++)
{
myObjectB[i].Comments = myObjectA[i].Comments;
}
Because myObjectB is an empty list. You are looping through the myObjectA list which might have one more item and in the first iteration of the loop it will try to execute code like
myObjectB[0].Comments = myObjectA[0].Comments;
Which will crash because there is no items in the myObjectB list and you are trying to access the first item(zeroth index), hence getting the Out of Range exception ! specifically the Index was out of range. Must be non-negative and less than the size of the collection. exception
Assuming both objectB and objectA has Comments property of same type, you can loop through the myObjectA list and for each item, create a new objectB object and add to the list (which was originally initalized as the empty list) using the Add method.
List<objectB> myObjectB = new List<objectB>();
for (var i=0; i < myObjectA.Count; i++)
{
var b = new objectB(); //create the object
b.Comments = myObjectA[i].Comments; // map the property values
myObjectB.Add(b); //add the object to the list
}
The above foreach code can be made to a one liner with LINQ projection
var bList = myObjectA.Select(x => new objectB { Comments = x.Comments }).ToList();
The variable bList will be a list of objectB objects.
You can do like this :
for (var i = 0; i < myObjectA.Count; i++)
{
myObjectB.Add(new objectB()
{
Comments = myObjectA[i].Comments
});
}
This way, with each iteration it'll add new objectB into myObjectB list.
With Linq, you can shorten your code :
myObjectB = myObjectA.Select(x => new objectB { Comments = x.Comments }).ToList();
I have a problem with using C#, if I initialize a certain list, lets say List<T> exampleList using another pre-existing list, lets say toModify like this: List<T> exampleList = new List<T>(toModify). When I later modify toModify list the newly created list also modifies itself. If it passes the value by reference shouldn't the value of exampleList stay the same since it was generated from the other one?
TLDR: Value of a list I initialize using another list(second list) changes when I change the second list. I come from a Java background and can't understand why this happens. Will I always have to use clone?
Let us use this example :
List<A> firstList = new List<A>()
{
new A() { Id = 3 },
new A() { Id = 5 }
};
List<A> secondList = new List<A>(firstList);
secondList[1].Id = 999;
Console.WriteLine(firstList[1].Id);
Output : 999
The main reason for this is that even though we created a new List<T> that points to a new memory allocated on heap it still works with references the point to same objects.
To create a list that points to new (!) objects with the same values we'd need to clone these elements somehow, one way to do it is to use LINQ .Select() method in order to create new objects and then a ToList() method to copy the list itself:
List<A> firstList = new List<A>()
{
new A() { Id = 3 },
new A() { Id = 5 }
};
List<A> secondList = firstList.Select(el => new A() { Id = el.Id }).ToList();
secondList[1].Id = 999;
Console.WriteLine(firstList[1].Id);
Output : 5
Yes.
You're creating a new list containing the same items as the old list. If you clear the first list, the items in the second stay.
But if you change a property for one of the items in the first list, then it is the same object in the second list.
So, both list are referencing the same items in memory. When you write list1[0].SomeProperty = 1 you're changing that using object reference that is the same in list2, so changes are reflected in the second list.
For how to clone a List and generate new references for items, check this SO Answer.
In the following line:
List<T> exampleList = new List<T>(toModify)
you create a list of T calling List<T>'s constructor that takes one argument of type IEnumerable<T>. For further info on the latter, please have a look here.
Method's arguments in C# are passed by default by value and not by reference. They can be passed by reference, but you have to explicitly state this in the signature of the corresponding method using the ref keyword and at the point you call this method, using again the same keyword. So the toModify is passed by value to the constructor of List<T>.
What's the importance of this?
In C# types can be divided into two categories (despite the fact that all types inherit from the System.Object):
Value types
Reference types
When we pass a value type as an argument, we pass a copy of it's value. Each modification we make in either the original value or in the copy of the original value is not reflected to one another. On the other hand, when we pass a reference type as an argument, we pass a copy of that reference. So now we have two references (pointers) that point to the same location in memory. That being said, it's clear that if we change any property of the object in which both references points to, this would be visible by both of them.
In your case, this is what is happening. toModify is a list of reference types (under the hood you have an array, whose items are references to other objects). So any change to the items of the initial list, toModify, is reflected to the list you construct based on this list.
A simple example that you could use to verify the above is the following:
public class Point
{
public int X { get; set; }
public int Y { get; set; }
public override string ToString() => $"X: {X}, Y: {Y}";
}
class Program
{
static void Main(string[] args)
{
var listA = new List<int> {1, 2, 3};
var listB = new List<int>(listA);
// Before the modification
Console.WriteLine(listA[0]); // prints 1
Console.WriteLine(listB[0]); // prints 1
listA[0] = 2;
// After the mofication
Console.WriteLine(listA[0]); // prints 2
Console.WriteLine(listB[0]); // prints 1
Console.ReadKey();
var pointsA = new List<Point>
{
new Point {X = 3, Y = 4},
new Point {X = 4, Y = 5},
new Point {X = 6, Y = 8},
};
var pointsB = new List<Point>(pointsA);
// Before the modification
Console.WriteLine(pointsA[0]); // prints X: 3, Y: 4
Console.WriteLine(pointsB[0]); // prints X: 3, Y: 4
pointsA[0].X = 4;
pointsA[0].Y = 3;
// After the modification
Console.WriteLine(pointsA[0]); // prints X: 4, Y: 3
Console.WriteLine(pointsB[0]); // prints X: 4, Y: 3
Console.ReadKey();
}
}
EDIT:
To whoever marked the question as duplicate. That question is for how to create a deep copy. My question was how to make sure a the copy constructor is called when copying a list of class elements.
I'm trying to make a deep copy of a List that contain custom class elements. If I have a List of strings I can just use
List<string> secondList = new List<string>(firstList);
and then freely modify the elements in the second list without effeting the ones in the firwst list. But when I try to do the same with a custom class type both lists get changed. To try and solve it I made a small test program that just has this class.
class TestClass
{
public string name;
public TestClass(string n)
{
name = n;
}
public TestClass(TestClass original)
{
name = original.name;
}
}
And all my program does is this
TestClass t = new TestClass("Name1");
List<TestClass> list1 = new List<TestClass>();
list1.Add(t);
List<TestClass> list2 = new List<TestClass>(list1);
list2[0].name = "Name2";
That last line of code changes the name of the first element in both lists, which I do no want.
The issue here is that your objects are reference types, and the lists hold references to those objects.
This means that even though your second list has a COPY of the references from the first list, the references are still pointing to the original objects.
In order to solve this, you must clone not the references in the lists but instead the actual objects that you have stored in the lists.
You have already defined a copy constructor for your class, so you can use that to make a deep copy of the list as follows:
var list2 = list1.Select(item => new TestClass(item)).ToList();
You create a reference with this line of Code:
List<TestClass> list2 = new List<TestClass>(list1);
But you won't like to use Call-by-Reference. You Need Call-by-Value
in this Approach.
so the working code in lambda-expression is the following one:
TestClass t = new TestClass("Name1");
List<TestClass> list1 = new List<TestClass>();
list1.Add(t);
List<TestClass> list2 = new List<TestClass>();
list2 = list1.Select(item => new TestClass(item)).ToList();
list2[0].name = "Name2";
Have fun with it...
Can anyone tell when to use Add() and AddRange() of ArrayList?
If you want to add a large number of values at one time, use AddRange.
If you are only adding a single value or adding values infrequently, use Add
Difference Between Add and AddRange
Add---------It is used to add the item into the list one by one.
AddRange-----------It is used to add the bulk of list item into the another list.
List<string>list1=new List<string>();//using Add
List<string>list2=new List<string>();//using AddRange
list1.Add("Malathi");
list1.Add("Sandhiya");
list1.Add("Ramya");
list1.Add("Mithra");
list1.Add("Dharshini");
list2.AddRange(list1);
output:
//The output of list1 contains
Malathi,
Sandhiya,
Ramya,
Mithra,
Dharshini
//The output of list2 Contains
Malathi,
Sandhiya,
Ramya,
Mithra,
Dharshini
C# List class represents a collection of a type in C#. List.Add(), List.AddRange(), List.Insert(), and List.InsertRange() methods are used to add and insert items to a List.
AddRange - AddRange adds an entire collection of elements. It can replace tedious foreach-loops that repeatedly call Add on List.
public virtual void AddRange (System.Collections.ICollection c);
Add - Add method adds an object to the end of the List.
public virtual int Add (object value);
Example: Now set an array of elements to be added to the list.
// array of 4 elements
int[] arr = new int[4];
arr[0] = 500;
arr[1] = 600;
arr[2] = 700;
arr[3] = 800;
Use the AddRange() method add the entire collection of elements in the list −
List<int> list = new List<int>();
list.AddRange(arr);
But if you want to use List.Add() method,
List<int> list = new List<int>();
list.Add(100);
list.Add(200);
list.Add(300);
list.Add(400);
For details, you can check Insert an Item into a C# List
If You want to add single variable in List, then Add() is used.
But if you want to add List or multiple variable in List, then AddRange() can be used
var t = (from t1 intable1
join t2 in table2 on t1.t1id equals t2.t2id
select new ABCViewModel
{
FirstName = t1.firstname,
LastName = t1.Lastname
})
.where(t2.age>35)
.ToList();
var s = (from t1 intable1
join t2 in table2 on t1.t1id equals t2.t2id
select new ABCViewModel
{
FirstName = t1.firstname,
LastName = t1.Lastname
})
.where(t2.age < 35)
.ToList();
t.AddRange(s);
return t;
It will add result of List s to List t along with result of List t.
Difference b/w Add() and AddRange() methods is very straight forward
Add() is used to add an element in the list.
AddRange() is used to add a range of elements(multiple elements) at once in the list.
Note: Multiple elements can be another entire Array, HashTable, SortedList, ArrayList, BitArray, Queue, and Stack.
namespace ConsoleApplication2
{
class Program
{
static void Main(string[] args)
{
//create the first arraylist
ArrayList arraylist1 = new ArrayList();
arraylist1.Add(5);
arraylist1.Add(7);
//create the second arraylist
ArrayList arraylist2 = new ArrayList();
arraylist2.Add("Five");//add the single value at time to the arraylist
arraylist2.Add("Seven");//add the single value at time to the arraylist
//perform AddRange method
arraylist1.AddRange(arraylist2);//adding the arraylist as bulk in another arraylist
// Display the values.
foreach (object i in arraylist1)//iterating the arraylist1 value to object
{
Console.WriteLine(i);
}
}
}
}