Deep copy of an object into List - c#

I have a loop:
List<A> list = new List<A>();
A obj = new A();
for (int i = 0; i < 10; ++i)
{
obj.num = i; // Assigns the current i to the num attribute inside obj
list.Add(obj);
}
However, in this case, whenever I modify obj, the previous instances of obj already added into the list will be modified. How do I write the code such that whatever that is added into the list has no more reference to the current value of obj?

You can create a new List<A> via Linq instead of adding:
List<A> list = Enumerable
.Range(0, 10)
.Select(i => new A() { num = i })
.ToList();
If you prefer adding
List<A> list = new List<A>();
for (int i = 0; i < 10; ++i)
list.Add(new A() {num = i}); // <- Adding new (copied) instance

you should move declaration of obj variable inside for loop
List<A> list = new List<A>();
for (int i = 0; i < 10; ++i)
{
A obj = new A();
obj.num = i; // Assigns the current i to the num attribute inside obj
list.Add(obj);
}
it is all just about variable scopes. here obj scope is inside a for loop iteration. if you want to use a variable between iterations you should define it out of for loop like the way you have declared obj before.

That's happening because probably A obj = new A(); is a ByReference object. So whenever you're in the loop, it's also changing the object you added on the List.
What you can do is either
Create the object inside the loop and then add it.
for (int i = 0; i < 10; ++i)
{
A obj = new A(); // create here so it's a new object always
obj.num = i; // Assigns the current i to the num attribute inside obj
list.Add(obj);
}
Make the A type IClonable
class A : ICloneable
{
public object Clone()
{
return this.MemberwiseClone();
}
}
and then just cast in before adding.
List<A> list = new List<A>();
A obj = new A();
obj.num = 0;
for (int i = obj.num; i < 10; ++i)
{
var clonedObj = obj.Clone() as A; // cast to be able to add in the collection
clonedObj.num = i;
list.Add(clonedObj);
}

Related

How can i dynamically create an objects of the class?

I have a class MyClass:
public class OPCTag
{
public string tagName;
public string tagOvationMatch;
public string tagValue;
}
I know how to create an object of class manually, but how can i dynamically create and objects of this class ? For example, to create it at the for cycle:
for (int i=0; i< 10; i++)
{
//CREATE OBJECT DYNAMICALLY
}
To get after it a 10 objects of MyClass.
If you mean simply creating an instance of a class always with the same type, then this will be enough for you:
List<OPCTag> list = new List<OPCTag>();
for (int i = 0; i < 10; i++)
{
// Create object of OPCTag
var obj = new OPCTag();
// Set value for 'tagName' property
obj.tagName = "New value of 'tagName'";
// Get value of 'tagName' property
var tagNameValue = obj.tagName;
list.Add(obj);
}
// Set value of 4th element 'tagName' property
list[4].tagName = "This is 4th element";
// Get value of 4th element 'tagName' property
var valueOf4thTag = list[4].tagName;
But if you want to create classes dynamically with unknown types, you should use reflection:
// Type namespace and name
string typeName = typeof(OPCTag).FullName; // MyNamespace.OPCTag
List<Object> list = new List<Object>();
for (int i = 0; i < 10; i++)
{
// Create object dynamically from string type
var obj = Type.GetType(typeName).GetConstructor(new Type[0]).Invoke(new object[0]);
// Set value for 'tagName' property
obj.GetType().GetProperty("tagName").SetValue(obj, "New value for 'tagName'");
// Get value from 'tagName' property
string tagNameValue = (string)obj.GetType().GetProperty("tagName").GetValue(obj);
list.Add(obj);
}
You can add your objects dynamically in a loop, but you have to create a list.
You can write something like that :
List<OPCTag> lstTag = new List<OPCTag>();
for(int i = 0; i<10 ; i++)
{
lstTag.Add(new OPCTag());
}
//Your class
public class OPCTag
{
public string tagName;
public string tagOvationMatch;
public string tagValue;
}
// Initialize new list object of type OPCTag
List<OPCTag> lstTag = new List<OPCTag>();
for(int i = 0; i<10 ; i++)
{
lstTag.Add(new OPCTag());
}
//To read value from lstTag based on index here I specify the 0 index / first value in list.
var firstIndexTagname = lstTag[0].tagName;
var firstIndexTagOvationMatch = lstTag[0].tagOvationMatch;
var firstIndexTagValue = lstTag[0].tagValue;
To create 10 objects of MyClass you can do, for example:
List<MyClass> list = new List<MyClass>();
for (int i = 0; i < 10; i++)
{
list.Add(new MyClass());
}
Though it's not "dynamically creating objects", just creating instances.
For Dictionary you should specify key and value. They can be of any type, not just int (usually string).
Dictionary<int, MyClass> dictionary = new Dictionary<int, MyClass>();
for (int i = 0; i < 10; i++)
{
dictionary.Add(i, new MyClass());
}

Avoiding duplicates in List within loop

I have a for loop which invokes a method within it. I add the return of this method to a list however I am getting duplicates in the list (the last return from the method call is all the items in the list). Presumably this is because the result object is the same instance. Is there a way around this?
IList<CarResult> carResults = new List<CarResult>();
for (int i = 0; i < cars.Count(); i++)
{
result = calculation.RunForCar(
engineSize[i],
yearOfManufacture[i],
carResults.Add(result);
}
return carResults;
}
I'm going to make a qualified guess and try to explain what's going on, without knowing exactly what's happening in your RunForCar().
Presumably this is because the result object is the same instance.
Probably yes.
Here's an example. It will not create new instances of Foo, but re-use the same instance over and over. So every time the name changes it changes the name on the reference. The list itself only contains the references, and therefore all the items in the list will be changed if you change the name on the reference.
var list = new List<Foo>();
var result = new Foo();
for(int i = 0; i < 5; i++)
{
result.Name = i.ToString();
list.Add(result);
}
foreach (var foo in list)
{
Console.WriteLine(foo.Name);
}
Output:
4
4
4
4
4
If we instead do like the code below, we assign result to a new reference, and then we leave the existing references untouched.
var list = new List<Foo>();
var result = new Foo();
for(int i = 0; i < 5; i++)
{
result = new Foo()
{
Name = i.ToString()
};
result.Name = i.ToString();
list.Add(result);
}
foreach (var foo in list)
{
Console.WriteLine(foo.Name);
}
Output:
0
1
2
3
4
Is there a way around this?
Yes, you can simply create a new instance of result for every loop. Without knowing more about either CarResult or RunForCar I cannot say when it's best to create the new instance. But here's an example:
IList<CarResult> carResults = new List<CarResult>();
for (int i = 0; i < cars.Count(); i++)
{
result = new CarResult();
result = calculation.RunForCar(
engineSize[i],
yearOfManufacture[i]); // Fixed type-o?
carResults.Add(result);
}
return carResults;
Alternatively you can have a local variable inside the loop.
IList<CarResult> carResults = new List<CarResult>();
for (int i = 0; i < cars.Count(); i++)
{
var result = new CarResult(); // Will not be accessible outside of loop.
result = calculation.RunForCar(
engineSize[i],
yearOfManufacture[i]); // Fixed type-o?
carResults.Add(result);
}
return carResults;
If the result is the same instance, you need to replace IList with HashSet
You need to create a new instance or result object on every pass of the loop in order to avoid adding it by reference to carResults list. Oterwise, all items in carResults will hold the reference to the same object which will contain the data from the last loop cycle.

After loop all elements same

I want to assign value to elements of my array. after running this, all elements of ListResults are same as last element of ListROI.
ListResults = new DataPoint[nROIrow];
DataPoint TempRes = new DataPoint();
System.Collections.ArrayList List = new System.Collections.ArrayList();
for (int i = 0; i < nROIrow; i++)
{
TempRes.X = ListROI[i].X;
TempRes.Y = ListROI[i].Y;
TempRes.u = dispROIcorr[i, 0];
TempRes.v = dispROIcorr[i, 1];
ListResults[i] = TempRes;
disp.Xpix = ListResults[i].X;
disp.Ypix = ListResults[i].Y;
disp.X = ListResults[i].X;
disp.Y = ListResults[i].Y;
disp.U = ListResults[i].u;
disp.V = ListResults[i].v;
List.Add(disp);
bSAVE.Enabled = true;
}
You only create a new DataPoint(); one time. So you end up with an array full of references to that same single instance.
The simple fix:
ListResults = new DataPoint[nROIrow];
//DataPoint TempRes = new DataPoint();
System.Collections.ArrayList List = new System.Collections.ArrayList();
for (int i = 0; i < nROIrow; i++)
{
DataPoint TempRes = new DataPoint();
...
ListResults[i] = TempRes;
var disp = new ...
disp.Xpix = ListResults[i].X;
....
List.Add(disp);
}
The problem with your code is that you are reusing the TempRes variable. When you perform the "List.Add" you are just adding a reference to it, and all these references are (obviously) the same. You also modify it, so each identical reference logically points to the same identical data.
Instead, write:
System.Collections.ArrayList List = new System.Collections.ArrayList();
for (int i = 0; i < nROIrow; i++)
{
DataPoint TempRes = new DataPoint();
...
Note also that ArrayList is generally considered to be deprecated since .NET 2.0 and you should be using List<T> instead.
do
disp = new ... // whatever
before assigning values to disp[i].???
actually what is happening is all the references in your List are referring to disp which is the single object that was created outside the for loop, hence all items in List are pointing to same disp object, hence same values.

Duplicate List<T>.Add(T item) Items

Why does aFooList contain five copies of the last item, instead of the five items I inserted?
Expected Output: 01234
Actual Output: 44444
using System;
using System.Collections.Generic;
namespace myTestConsole {
public class foo {
public int bar;
}
class Program {
static void Main(string[] args) {
foo aFoo = new foo(); // Make a foo
List<foo> aFooList = new List<foo>(); // Make a foo list
for (int i = 0; i<5; i++) {
aFoo.bar = i;
aFooList.Add(aFoo);
}
for (int i = 0; i<5; i++) {
Console.Write(aFooList[i].bar);
}
}
}
}
You have added the same item, aFoo, 5 times. When you modify contents of a reference-type object you don't create new copies, you modify the same object.
List<foo> aFooList = new List<foo>(); // Make a foo list
for (int i = 0; i<5; i++) {
foo aFoo = new foo(); // Make a foo
aFoo.bar = i;
aFooList.Add(aFoo);
}
You are still modifying your aFoo while it is in the list.
You've added a reference to the same object to your list 5 times, each time modify the value of bar. Add this line after aFooList.Add(aFoo); to see the effect each time you add a foo to the list.
Console.WriteLine(string.Join("", foos.Select(f => f.bar)));
For what it's worth, it's a one-liner (spaced nicely for readability) with Linq.
var foos = Enumerable.Range(0, 5)
.Select(n => new foo {bar = n})
.ToList();
Complete example:
foo aFoo = new foo(); // Make a foo
List<foo> aFooList = new List<foo>(); // Make a foo list
Console.WriteLine("\nUsing aFooList");
for (int i = 0; i < 5; i++)
{
aFoo.bar = i;
aFooList.Add(aFoo);
Console.WriteLine(string.Join("", aFooList.Select(f => f.bar)));
}
var foos = Enumerable.Range(0, 5).Select(n => new foo { bar = n }).ToList();
Console.WriteLine("\nUsing foos");
Console.WriteLine(string.Join("", foos.Select(f => f.bar)));
Console.ReadLine();
Output:
Using aFooList
0
11
222
3333
44444
Using foos
01234
Your variable 'aFoo' is basically a pointer to a location in memory. Without "newing" up another instance (malloc) you're modifying the same location in memory and add the same pointer 5 times.
The "new" keyword fullfills the function as far as programmers are concerned in C# as malloc does in C. It will get a new memory location and make aFoo point to that location, instead of the old one.
From MSDN:
The new operator is used to create objects and invoke constructors
MSDN

Dynamic Initialize in c#

I've a class
class sampleClass
{
...........
...........
public sampleClass()
{.........}
}
and in another class i created an array like
sampleClass[] X=new sampleClass[]{new sampleClass(),new sampleClass()}
here i gave 2 instance of the constructor. i need this dynamically..
that is the size of the array should be dynamically changed
It sounds like you want something like:
int size = // whatever
SampleClass[] array = new SampleClass[size];
for (int i = 0; i < size; i++)
{
array[i] = new SampleClass();
}
EDIT: If you really want to avoid a for loop, you could do something like:
SampleClass[] array = Enumerable.Range(0, size)
.Select(x => new SampleClass())
.ToArray();
... but I don't think that's actually better than using a loop.
This is just a syntactic sugar, you can gain the same using your own code:
sampleClass[] X = new sampleClass[num];
for(int i = 0; i < num; i++)
{
X[i] = new sampleClass();
}
You can initialize the array using a loop:
sampleClass[] X = new sampleClass[123];
for (int i = 0; i < X.Length; ++i)
X[i] = new sampleClass();
If your class was a value type the array is initialized when it is allocated:
struct sampleStruct { ... }
sampleStruct[] X = new sampleStruct[123];
// No need to initialize every array cell.
However, using a struct instead of a class is not something you should do simply to avoid a loop. You can read more about value types on MSDN.

Categories

Resources