c# List<myObject> myList.copyTo() keeps a reference? - c#

I've got a List and I used .copyTo() method. So it copies my List into one dimensional array.
So I loop this array and add each myObject to another List, then I'm changing things in this new List.
After this I'm showing the difference between the new values in my second List and the old values that are in my first List. But there is always no difference. So I'm thinking that the copyTo() method keeps a reference.
Are there other methods that doesn't keep a reference?

Yes. .CopyTo() performs a shallow copy, which means it copies the references. What you need is a deep copy, by cloning each object.
The best way is to make you myObject class implement IClonable
public class YourClass
{
public object Clone()
{
using (var ms = new MemoryStream())
{
var bf = new BinaryFormatter();
bf.Serialize(ms, this);
ms.Position = 0;
object obj = bf.Deserialize(ms);
ms.Close();
return obj;
}
}
}
Then you can cole .Clone() on each object and add that to a new List.
List<YourClass> originalItems = new List<YourClass>() { new YourClass() };
List<YourClass> newItemList = originalItems.Select(x => x.Clone() as YourClass).ToList();

If you've got a List of reference types, and you use the the CopyTo method to copy to an array, the contents of the List which are references will be copied across, so when you modify the objects in your array, they'll still refer to the same objects on the heap which are referenced from your list.

Related

Deep copy of a list with class elements

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...

How to assign List<T> without it being a reference to the original List<T>?

For example
List<string> name_list1 = new List<string>();
List<string> name_list2 = new List<string>();
later in the code:
name_list1.Add("McDonald");
name_list1.Add("Harveys");
name_list1.Add("Wendys");
name_list2 = name_list1; // I make a copy of namelist1 to namelist2
So, from this point I would like to keep adding element or making changes in name_list2 without affecting name_list1. How do I do that?
name_list2 = new List<string>(name_list1);
This will clone the list.
Edit: This solution only works for primitive types. For objects, see other responses below.
Another Options is : Deep Cloning
public static T DeepCopy<T>(T item)
{
BinaryFormatter formatter = new BinaryFormatter();
MemoryStream stream = new MemoryStream();
formatter.Serialize(stream, item);
stream.Seek(0, SeekOrigin.Begin);
T result = (T)formatter.Deserialize(stream);
stream.Close();
return result;
}
so,
you can use :
name_list2 = DeepCopy<List<string>>(name_list1);
OR:
name_list2 = DeepCopy(name_list1);
will also work.
For Primitive Types you can do this:
List<string> CopyList = new List<string>(OriginalList);
For non-primitve/user-difined types you can do this:
List<Person> CopyList = new List<Person>();
foreach(var item in OriginalList)
{
CopyList.Add(new Person {
Name = item.Name,
Address = item.Address
});
}
name_list2 = new List<string>(name_list1); // Clone list into a different object
At this point, the two lists are different objects. You can add items to list2 without affecting list1
The problem is the assignment. Until the assignment name_list2 = name_list1;, you have two different List objects on the heap pointed to by the variables name_list1 and name_list2. You fill up name_list1, which is fine. But the assignment says, "make name_list2 point to the same object on the heap as name_list1." The List that name_list2 used to point to is no longer accessible and will be garbage collected. What you really want is to copy the contents of name_list1 into name_list2. You can do this with List.AddRange. Note that this will result in a "shallow" copy, which is fine for the example you cite, where the list contents are strings, but may not be what you want when the list members are more complex objects. It all depends on your needs.
Based on #Mrunal answer I created an extension method:
public static T Clone<T>(this T source)
{
// Don't serialize a null object, simply return the default for that object
if (source == null)
{
return default;
}
// initialize inner objects individually
// for example in default constructor some list property initialized with some values,
// but in 'source' these items are cleaned -
// without ObjectCreationHandling.Replace default constructor values will be added to result
var deserializeSettings = new JsonSerializerSettings { ObjectCreationHandling = ObjectCreationHandling.Replace };
return JsonConvert.DeserializeObject<T>(JsonConvert.SerializeObject(source), deserializeSettings);
}
And you can call it like this:
L2 = L1.Select(x => x.Clone()).ToList();
I like linq for this...
If list elements are primitives or structures then...
L2 = L1.ToList()
If list elements are classes then...
L2 = L1.Select(x => x.Copy()).ToList();
Where Copy could simply be a shallow copy exposure of MemberWiseClone, or it could be some implementation of a deep copy.
I prefer Json converter method to serialize and deserialize, this way you don't have to mark the classes for serialization, especially you have numerous child classes.
https://www.newtonsoft.com/json/help/html/SerializingJSON.htm
Here is an alternative solution:
List<string> name_list1 = new List<string>();
List<string> name_list2 = new List<string>();
name_list1.Add("McDonald");
name_list1.Add("Harveys");
name_list1.Add("Wendys");
name_list2.AddRange(name_list1.ToArray());
The ToArray() method copies 'name_list1' to a new array, which we then add to name_list2 via the AddRange() method.
For primitive types:
List ClonedList = new list(OriginalList);
For non-primitive/User Defined types:
We need to perform a deep copy:
Deep Copy is used to make a complete deep copy of the internal reference types, for this we need to configure the object returned by MemberwiseClone().
Step1- In your class inherit from ICloneable:
public class MyClass:ICloneable
Step2- Implement method
public MyClass Clone()
{
MyClass MyClassObj =new MyClass();
MyClassObj.Property1 = this.Property1;
.
.
MyClassObj.Property_N = this.Property_N;
return MyClass;
}
Step3- now clone your List
List<MyClass> MyClassClone = new List<MyClass>();
for(i=0; i<Count; i++)
{
MyClassClone.Add(OriginalClaaObj[i].Clone());
}
This will make deep copy of each item of the object.
None of the above solutions worked for me when using lists of class objects.
This can be used for copying any object to another object with shared property names.
public static void ObjectToObject(object source, object destination)
{
// Purpose : Use reflection to set property values of objects that share the same property names.
Type s = source.GetType();
Type d = destination.GetType();
const BindingFlags flags = BindingFlags.Public | BindingFlags.Instance;
var objSourceProperties = s.GetProperties(flags);
var objDestinationProperties = d.GetProperties(flags);
var propertyNames = objSourceProperties
.Select(c => c.Name)
.ToList();
foreach (var properties in objDestinationProperties.Where(properties => propertyNames.Contains(properties.Name)))
{
try
{
PropertyInfo piSource = source.GetType().GetProperty(properties.Name);
properties.SetValue(destination, piSource.GetValue(source, null), null);
}
catch (Exception ex)
{
throw;
}
}
}
public static List<T> CopyList<T>(this List<T> lst)
{
List<T> lstCopy = new List<T>();
foreach (var item in lst)
{
var instanceOfT = Activator.CreateInstance<T>();
ObjectToObject(item, instanceOfT);
lstCopy.Add(instanceOfT);
}
return lstCopy;
}
For lists use this:
list2 = list1.CopyList();
If both the lists are of the same complex type then you can do something like below:-
SomeClass List2 = new List();
List1.ForEach(u => List2.Add(u));
What I am doing is to loop through each element of List1 and keep adding it to List2.
I believe this is the shortest way to do it.
While it could be potential performance-threat solution, but it would copy the values property-by-property eloquently.
using Newstonsoft.Json;
ClassA classA = new ClassA();
ClassA classACopyWithoutReference = JsonConvert.DeserializeObject<ClassA>(JsonConvert.SerializeObject(classA));
this solution works For complex objects (Replace T with name of your Type):
list2 = list1.Concat(new List<T> { object }).ToList();
or:
list2 = list1.ToArray().Append(object).ToList()
You can clone the complex object by serialize and deserialize it, it will remove you object reference and create new object without reference
using Newstonsoft.Json;
List<string> name_list1 = new List<string>();
name_list1.Add("McDonald");
name_list1.Add("Harveys");
name_list1.Add("Wendys");
name_list2 = name_list1;
List<string> name_list2 = JsonConvert.DeserializeObject<List<string>>
(JsonConvert.SerializeObject(name_list1)); // Ii make a copy of namelist1 to namelist2
this is working for me using LINQ...
lst1= lst2.ToList();

How to keep a Generic list unmodified when its copy is modified?

When I create a copy of the original list lstStudent in lstCopy and send the lstCopy to modification function, the lstStudent also gets modified. I want to keep this list unmodified.
List<Student> lstStudent = new List<Student>();
Student s = new Student();
s.Name = "Akash";
s.ID = "1";
lstStudent.Add(s);
List<Student> lstCopy = new List<Student>(lstStudent);
Logic.ModifyList(lstCopy);
// "Want to use lstStudent(original list) for rest part of the code"
public static void ModifyList(List<Student> lstIntegers) {
foreach (Student s in lstIntegers) {
if (s.ID.Equals("1")) {
s.ID = "4"; s.Name = "APS";
}
}
}
You can also achieve this without cloneable interface by using binary formatter:
NOTE: ALL classes as part of the object graph must be marked Serializable.
void Main()
{
var student1=new Student{Name="Bob"};
var student2=new Student{Name="Jim"};
var lstStudent=new List<Student>();
lstStudent.Add(student1);
lstStudent.Add(student2);
var lstCopy=new List<Student>(lstStudent);
var clone=Clone(lstStudent);
student1.Name="JOE";
lstCopy.Dump();
lstStudent.Dump();
clone.Dump();
}
public List<Student> Clone(List<Student> source)
{
BinaryFormatter bf=new BinaryFormatter();
using(var ms=new MemoryStream())
{
bf.Serialize(ms,source);
ms.Seek(0,0);
return (List<Student>)bf.Deserialize(ms);
}
}
[Serializable]
public class Student
{
public string Name { get; set; }
}
OUTPUT:
5List<Student> (2 items) 4
Name
JOE
Jim
5List<Student> (2 items) 4
Name
JOE
Jim
5List<Student> (2 items) 4
Name
Bob
Jim
code is formatted for dumping into LINQPad
EDIT:
This is an option in situations where it's not possible to implement ICloneable. When applicable, code to interfaces. In other words, you can implement ICloneable on the student object and use the BinaryFormatter logic in the Clone() method; However, As a developer, you have the option to decide for yourself what you want to do. Options are not necessarily advice and advice isn't always an option. There are times when you must do what it takes to complete a task and that's where options come into play.
This is a pretty widely accepted, deep cloning, method:
How do you do a deep copy of an object in .NET (C# specifically)?
I would take a look at ICloneable. What you're after is a "deep copy". Lots of good information in this post:
How do I clone a generic list in C#?
Just another quick way to copy your List using LINQ
List<student> oldList = new List<student> { new student{
id=122,
name="John"} };
IEnumerable<student> copy= oldList.Select(item => new student{
id = item.id,
name = item.name });
List<student> newList= new List<student>(copy);
But the best option would still be implementing ICloneable to deep copy your objects
If your Student type is a class (reference type), a list will only contain references to those instances. This means that when you make a copy of your list, the copied list will also have only references that still point to the same Student instances. By copying your list you simply duplicated your references but not the instances. What you have after the copy is something like this:
List 1 List 2 instance S1
ref to S1 ref to S1 Name: Akash
ref to S2 ref to S2 ...
... ...
So if you do something like list1[0].Name = "Jim", you'll update the instance S1 and you'll see the change in both lists, since both lists refer to the same set of instances.
What you need to do is create a clone of not only the list in this case but all the objects inside the list - you need to clone all your Student objects as well. This is called a deep copy. Something like this:
class StudentList : List<Student>, ICloneable
{
public object Clone ()
{
StudentList oNewList = new StudentList ();
for ( int i = 0; i < Count; i++ )
{
oNewList.Add ( this[i].Clone () as Student );
}
return ( oNewList );
}
}
You call this like so:
StudentList oClonedList = lstStudent.Clone () as StudentList;
You also need to make your Student class cloneable by implementing the ICloneable interface.
Don't forget, though, that after this, you'll have 2 separate lists with 2 independent sets of Student objects - modifying one Studentinstance will have no effect on students in your other list.
You want a deep copy of the list. Right now, it is a shallow copy. You just have two references to the same variable. There is no simple way to get a deep copy in C# like in languages such as C++. One method to get a deep copy is by serializing and deserializing the first list. The following is a templated function to get a deep copy of an object.
public static T getDeepCopy<T>( T objectToCopy )
{
T temp;
using ( MemoryStream ms = new MemoryStream() )
{
BinaryFormatter formatter = new BinaryFormatter();
formatter.Serialize( ms, objectToCopy );
ms.Position = 0;
temp = (T)formatter.Deserialize( ms );
}
return temp;
}
You will need to include these namespaces as well:
using System.IO;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
You can then call the function like this:
lstCopy = getDeepCopy<List<Student>>(lstStudents);

Read HttpRuntime.Cache item as read-only

I am using a HttpRuntime.Cache to store a list of objects that will be accessing frequently across sessions.
I use the following line of code to get the item from the cache:
List<chartData_Type> _chartData =
(List<chartData_Type>)HttpRuntime.Cache.Get("rollingMonth");
But, unfortunately when I update the _chartData, it updates the cached item too.
How can I simply get a copy of the cached item?
That is the way which .NET works because Cache just reference to the pointer of List. Don't know whether you chartData_Type is value type or reference type.
If value type, it is easy to use:
List<chartData_Type> list = new List<chartData_Type>(_chartData);
But if reference type, it comes to complicated, you need to implement DeepCopy method for your class, then do DeepCopy for each object in list.
DeepClone method:
public static class CloneHelper
{
public static T DeepClone<T>(T obj)
{
using (var ms = new MemoryStream())
{
var formatter = new BinaryFormatter();
formatter.Serialize(ms, obj);
ms.Position = 0;
return (T) formatter.Deserialize(ms);
}
}
}
In order to use this method, class chartData_Type must be marked [Serializable]:
[Serializable]
class chartData_Type
{}
So, you can do deep clone manually:
var cloneChartData = _chartData.Select(d =>
CloneHelper.DeepClone<chartData_Type>(d))
.ToList();
Use:
List<chartData_Type> list = new List<chartData_Type>(_chartData);
It will copy all items from _chartData to list.
List is a reference type and _chartData holds the address of the original object stored in the cache. That is why when you update _chartData, it updates the cached object too. If you want a separate object then clone the cached object. See below reference
http://www.codeproject.com/Articles/33364/ASP-NET-Runtime-Cache-Clone-Objects-to-Preserve-Ca
http://www.codeproject.com/Articles/45168/ASP-NET-Runtime-Cache-Clone-Objects-to-Preserve-Ca

How to deep copy a matrix in C#?

I got a List<List<CustomClass>>, where CustomClass is a reference type.
I need to make a full deep copy of this matrix into a new one. Since I want a deep copy, each CustomClass object in the matrix has to be copied into the new matrix.
How would you do that in an efficient way?
For a CustomClass that implements ICloneable, this isn't very difficult:
var myList = new List<List<CustomClass>>();
//populate myList
var clonedList = new List<List<CustomClass>>();
//here's the beef
foreach(var sublist in myList)
{
var newSubList = new List<CustomClass>();
clonedList.Add(newSubList);
foreach(var item in sublist)
newSublist.Add((CustomClass)(item.Clone()));
}
You can make this work in a similar way with any "DeepCopy"-type method, if you feel you don't want to implement ICloneable (I would recommend using the built-in interface though).
One easier way to serialize the whole object and then deserialize it again, try this extension method:
public static T DeepClone<T>(this T source)
{
if (!typeof(T).IsSerializable)
{
throw new ArgumentException("The type must be serializable.", "source");
}
// Don't serialize a null object, simply return the default for that object
if (Object.ReferenceEquals(source, null))
{
return default(T);
}
IFormatter formatter = new BinaryFormatter();
Stream stream = new MemoryStream();
using (stream)
{
formatter.Serialize(stream, source);
stream.Seek(0, SeekOrigin.Begin);
return (T)formatter.Deserialize(stream);
}
}
USAGE
List<List<CustomClass>> foobar = GetListOfListOfCustomClass();
List<List<CustomClass>> deepClonedObject = foobar.DeepClone();
There are two possibilities:
Implement the ICloneable interface on your CustomClass, then you can clone your objects.
If the class can be serialized, serialize it to a memory stream and deserialize it from there. That will create a copy of it.
I would prefer to take the first alternative, because I think serializing / deserializing is slower than cloning via ICloneable.
Assuming you have a Copy method which can duplicate CustomClass objects:
var newMatrix = oldMatrix
.Select(subList => subList.Select(custom => Copy(custom)).ToList())
.ToList();

Categories

Resources