Deep copy of List<T> - c#

I'm trying to make a deep copy of a generic list, and am wondering if there is any other way then creating the copying method and actually copying over each member one at a time. I have a class that looks somewhat like this:
public class Data
{
private string comment;
public string Comment
{
get { return comment; }
set { comment = value; }
}
private List<double> traceData;
public List<double> TraceData
{
get { return traceData; }
set { traceData = value; }
}
}
And I have a list of the above data, i.e List<Data>. What I'm trying to do is plot a trace data of the subset of List onto a graph, possibly with some scaling or sweeping on the data. I obviously don't need to plot everything in the list because they don't fit into the screen.
I initially tried getting the subset of the list using the List.GetRange() method, but it seems that the underneath List<double> is being shallow copied instead of deep copied. When I get the subset again using List.GetRange(), I get previously modified data, not the raw data retrieved elsewhere.
Can anyone give me a direction on how to approach this? Thanks a lot.

The idiomatic way to approach this in C# is to implement ICloneable on your Data, and write a Clone method that does the deep copy (and then presumably a Enumerable.CloneRange method that can clone part of your list at once.) There isn't any built-in trick or framework method to make it easier than that.
Unless memory and performance are a real concern, I suggest that you try hard to redesign it to operate on immutable Data objects, though, instead. It'll wind up much simpler.

You can try this
public static object DeepCopy(object obj)
{
if (obj == null)
return null;
Type type = obj.GetType();
if (type.IsValueType || type == typeof(string))
{
return obj;
}
else if (type.IsArray)
{
Type elementType = Type.GetType(
type.FullName.Replace("[]", string.Empty));
var array = obj as Array;
Array copied = Array.CreateInstance(elementType, array.Length);
for (int i = 0; i < array.Length; i++)
{
copied.SetValue(DeepCopy(array.GetValue(i)), i);
}
return Convert.ChangeType(copied, obj.GetType());
}
else if (type.IsClass)
{
object toret = Activator.CreateInstance(obj.GetType());
FieldInfo[] fields = type.GetFields(BindingFlags.Public |
BindingFlags.NonPublic | BindingFlags.Instance);
foreach (FieldInfo field in fields)
{
object fieldValue = field.GetValue(obj);
if (fieldValue == null)
continue;
field.SetValue(toret, DeepCopy(fieldValue));
}
return toret;
}
else
throw new ArgumentException("Unknown type");
}
Thanks to DetoX83 article on code project.

If IClonable way is too tricky for you. I suggest converting to something and back. It can be done with BinaryFormatter or a Json Converter like Servicestack.Text since it is the fastest one in .Net.
Code should be something like this:
MyClass mc = new MyClass();
string json = mc.ToJson();
MyClass mcCloned = json.FromJson<MyClass>();
mcCloned will not reference mc.

The most easiest (but dirty) way is to implement ICloneable by your class and use next extension method:
public static IEnumerable<T> Clone<T>(this IEnumerable<T> collection) where T : ICloneable
{
return collection.Select(item => (T)item.Clone());
}
Usage:
var list = new List<Data> { new Data { Comment = "comment", TraceData = new List { 1, 2, 3 } };
var newList = list.Clone();

another thing you can do is mark your class as serializable and use binary serialization.
Here is a working example
public class Program
{
[Serializable]
public class Test
{
public int Id { get; set; }
public Test()
{
}
}
public static void Main()
{
//create a list of 10 Test objects with Id's 0-10
List<Test> firstList = Enumerable.Range(0,10).Select( x => new Test { Id = x } ).ToList();
using (var stream = new System.IO.MemoryStream())
{
var binaryFormatter = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
binaryFormatter.Serialize(stream, firstList); //serialize to stream
stream.Position = 0;
//deserialize from stream.
List<Test> secondList = binaryFormatter.Deserialize(stream) as List<Test>;
}
Console.ReadKey();
}
}

If you make your objects immutable you don't need to worry about passing around copies of them, then you could do something like:
var toPlot = list.Where(d => d.ShouldBePlotted());

Since your collection is mutable, you need to implement the deep copy programmatically:
public class Data
{
public string Comment { get; set; }
public List<double> TraceData { get; set; }
public Data DeepCopy()
{
return new Data
{
Comment = this.Comment,
TraceData = this.TraceData != null
? new List<double>(this.TraceData)
: null;
}
}
}
The Comment field can be shallow copied because its already an immutable class. You need to create a new list for TraceData, but the elements themselves are immutable and require no special handling to copy them.
When I get the subset again using
List.GetRange(), I get previously
modified data, not the raw data
retrieved elsewhere.
Use your new DeepCopy method as such:
var pointsInRange = dataPoints
.Select(x => x.DeepCopy())
.GetRange(start, length);

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace DeepListCopy_testingSome
{
class Program
{
static void Main(string[] args)
{
List<int> list1 = new List<int>();
List<int> list2 = new List<int>();
//populate list1
for (int i = 0; i < 20; i++)
{
list1.Add(1);
}
///////
Console.WriteLine("\n int in each list1 element is:\n");
///////
foreach (int i in list1)
{
Console.WriteLine(" list1 elements: {0}", i);
list2.Add(1);
}
///////
Console.WriteLine("\n int in each list2 element is:\n");
///////
foreach (int i in list2)
{
Console.WriteLine(" list2 elements: {0}", i);
}
///////enter code here
for (int i = 0; i < list2.Count; i++)
{
list2[i] = 2;
}
///////
Console.WriteLine("\n Printing list1 and list2 respectively to show\n"
+ " there is two independent lists,i e, two differens"
+ "\n memory locations after modifying list2\n\n");
foreach (int i in list1)
{
Console.WriteLine(" Printing list1 elements: {0}", i);
}
///////
Console.WriteLine("\n\n");
///////
foreach (int i in list2)
{
Console.WriteLine(" Printing list2 elements: {0}", i);
}
Console.ReadKey();
}//end of Static void Main
}//end of class
}

One quick and generic way to deeply serialize an object is to use JSON.net. The following extension method allows serializing of a list of any arbitrary objects, but is able to skip Entity Framework navigation properties, since these may lead to circular dependencies and unwanted data fetches.
Method
public static List<T> DeepClone<T>(this IList<T> list, bool ignoreVirtualProps = false)
{
JsonSerializerSettings settings = new JsonSerializerSettings();
if (ignoreVirtualProps)
{
settings.ContractResolver = new IgnoreNavigationPropsResolver();
settings.PreserveReferencesHandling = PreserveReferencesHandling.None;
settings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
settings.Formatting = Formatting.Indented;
}
var serialized = JsonConvert.SerializeObject(list, settings);
return JsonConvert.DeserializeObject<List<T>>(serialized);
}
Usage
var clonedList = list.DeepClone();
By default, JSON.NET serializes only public properties. If private properties must be also cloned, this solution can be used.
This method allows for quick (de)serialization of complex hierarchies of objects.

Related

Sum up all the properties of a collection and dynamically assigned it to another object

I have a collection of object in lst of type DataResponse and what I would like to do is sum up all the properties that are int and decimal of this collection and assign the result of each property to another object DataContainerResponse that has the same exact property names(and types) as the those that are being summed up.
I can do this manually by typing out each property by hand and do a .Sum(s=>s.<propertyname>. But that so 90s. Below is my fruitless attempt to juice it out. Frankly, I never assigned a var to a lambda expression before and I don't even know if it's possible .Sum(s=><var name>);
public DataAggragationResponse doAggregation(List<DataResponse> lst)
{
if (lst.Count == 0)
return null;
DataContainerResponse rd = new DataContainerResponse();
//If I do it manually typing each prop by hand.
rd.VIOL = lst.Sum(s => s.VIOL);
//Automation!!!
foreach (PropertyInfo propertyInfo in typeof(DataResponse).GetProperties())
{
rd.GetType().GetProperties().SetValue(lst.Sum(s => propertyInfo.Name[0]));
}
}
If you want to go with full reflection, you can try something like the following. I didnt optimize the code, did it as fast as I can. So sorry for the messy look and Im assuming the property names are same in the aggregated result class and the unit class that you are aggregating against.
class Program
{
static void Main(string[] args)
{
var list = new List<DataResponse>();
list.Add(new DataResponse() { Stuff = 1, Stuff2 = 2 });
list.Add(new DataResponse() { Stuff = 1, Stuff2 = 2 });
Stopwatch watch = new Stopwatch();
watch.Start();
var response = DoAggregationReflection(list);
watch.Stop();
Console.WriteLine(watch.Elapsed.TotalMilliseconds);
watch.Reset();
watch.Start();
var response2 = DoAggregation(list);
watch.Stop();
Console.WriteLine(watch.Elapsed.TotalMilliseconds);
}
public static DataAggragationResponse DoAggregationReflection(List<DataResponse> lst)
{
if (lst.Count == 0)
return null;
DataAggragationResponse aggrResponse = new DataAggragationResponse();
var responseType = typeof(DataResponse);
var aggrResponseType = typeof(DataAggragationResponse);
foreach (PropertyInfo propertyInfo in typeof(DataResponse).GetProperties())
{
aggrResponseType.GetProperty(propertyInfo.Name).SetValue(aggrResponse, lst.Sum(x => (int)responseType.GetProperty(propertyInfo.Name).GetValue(x)));
}
return aggrResponse;
}
public static DataAggragationResponse DoAggregation(List<DataResponse> lst)
{
if (lst.Count == 0)
return null;
DataAggragationResponse aggrResponse = new DataAggragationResponse();
aggrResponse.Stuff = lst.Sum(x => x.Stuff);
aggrResponse.Stuff2 = lst.Sum(x => x.Stuff2);
return aggrResponse;
}
}
public class DataResponse
{
public int Stuff { get; set; }
public int Stuff2 { get; set; }
}
public class DataAggragationResponse
{
public int Stuff { get; set; }
public int Stuff2 { get; set; }
}
But, as a suggestion, if you want to go with this approach, its better if you can cache all the reflection invokes you're making as they are costly. And the 90's approach would still win in benchmark. Like the example above would benchmark like the following with the simple StopWatch.
1.8193
0.4476
Press any key to continue . . .
The first one is the execution time of DoAggregationReflection and the last one is the execution time of DoAggregation. You can optimize the reflection one as much as you want but I think it would still fail to compete with the basic one.
Sometime's the 90's are way better. ;) Although you'd still use LINQ to do the actual summation so that's not that 90's anymore as LINQ was born in 2007 according to wikipedia.
Hopefully this can help you. I wish I had kept the SO link to the question I pulled this from a while ago. Sorry to the original poster for not mentioning his/her name.
using System.Reflection;
public static Dictionary<string, string> GetPropertiesValue(object o)
{
Dictionary<string, string> PropertiesDictionaryToReturn = new Dictionary<string, string>();
foreach (MemberInfo itemMemberInfo in o.GetType().GetMembers())
{
if (itemMemberInfo.MemberType == MemberTypes.Property)
{
//object PropValue = GetPropertyValue(OPSOP, item.Name);
//string itemProperty = itemMemberInfo.Name;
//string itemPropertyValue = o.GetType().GetProperty(itemMemberInfo.Name).GetValue(o, null).ToString();
//Console.WriteLine(itemProperty + " : " + itemPropertyValue);
PropertiesDictionaryToReturn.Add(itemMemberInfo.Name, o.GetType().GetProperty(itemMemberInfo.Name).GetValue(o, null).ToString());
}
}
return PropertiesDictionaryToReturn;
}
It's not exactly what you need but, I think you could adapt it.
I would rather take a different approach. I would dynamically build and compile (once) something like this:
Func<DataContainerResponse, DataResponse, DataContainerResponse> aggregateFunc =
(result, item) =>
{
result.Prop1 += item.Prop1;
result.Prop2 += item.Prop2;
...
result.PropN += item.PropN;
return result;
}
(if you wonder why the signature is like the above, the answer is - because it can be used directly for the following Aggregate overload).
Here is how it can be done:
static readonly Func<DataContainerResponse, DataResponse, DataContainerResponse>
AggregateFunc = BuildAggregateFunc();
static Func<DataContainerResponse, DataResponse, DataContainerResponse> BuildAggregateFunc()
{
var result = Expression.Parameter(typeof(DataContainerResponse), "result");
var item = Expression.Parameter(typeof(DataResponse), "item");
var propertyTypes = new HashSet<Type> { typeof(decimal), typeof(int) };
var statements = item.Type.GetProperties()
.Where(p => propertyTypes.Contains(p.PropertyType))
.Select(p => Expression.AddAssign(
Expression.Property(result, p.Name),
Expression.Property(item, p)));
var body = Expression.Block(statements
.Concat(new Expression[] { result }));
var lambda = Expression.Lambda<Func<DataContainerResponse, DataResponse, DataContainerResponse>>(
body, result, item);
return lambda.Compile();
}
and the usage is simple:
public DataContainerResponse DoAggregation(List<DataResponse> source)
{
return source.Aggregate(new DataContainerResponse(), AggregateFunc);
}

Get access to my derived class members

I have several classes that inhabit from this class:
public abstract class Class1
{
private string _protocol;
private static List<Plus> _class1Objects;
public string Protocol
{
get { return _protocol; }
set { _protocol = value; }
}
public static List<Plus> Class1Objects
{
get { return _class1Objects; }
set { _class1Objects = value; }
}
}
And the derive class:
public class Class2 : Plus
{
public bool name;
public int id;
}
public Webmail(string name, int id)
{
if (Class1Objects == null)
Class1Objects = new List<class1>();
.....
Class1Objects.Add(this);
}
And after my list is full of Class1Objects:
for (int i = 0; i < Class1.Class1Objects.Count; i++)
{
if (Class1.Class1Objects[i].GetType() == typeof(Class2))
}
(Class2)Class1.Class1Objects[i].
}
}
Here after (Class2)Class1.Class1Objects[i]. i cannot see my Class2 memners
You need one additional paranthese:
((Class2)Class1.Class1Objects[i]).
At the moment it is read as the following:
(Class2)(Class1.Class1Objects[i].) //<= at the '.' it is still a class1
BUT as David said in his comment: If all are of type Class2 it should be a collection of that type and if not you should check the type, altogether with foreach:
foreach(var item in Class1.Class1Objects)
{
if(item is Class2)
((Class2)Class1.Class1Objects[i]).
}
It would be cleaner to use as:
for (int i = 0; i < Class1.Class1Objects.Count; i++)
{
var c2 = Class1.Class1Objects[i] as Class2;
if (c2!=null)
}
c2.<whatever was meant to come after the .>
}
}
You might also want to consider switching to foreach unless there's a specific reason you want to manually extract each element from the List, e.g. if you're actually storing new values back into the list.
The correct syntax would be:
((Class2)Class1.Class1Objects[i]).name;
Because in your case, when you type something like this:
(Class2)Class1.Class1Objects[i].name;
You try to access the member name of Class1.Class1Objects[i], and only after that you try to cast it to Class2.
Also, the whole loop would be much simpler if you used foreach:
using System.Linq;
foreach(Class2 c in Class1.Class1Objects.OfType<Class2>())
{
Console.WriteLine(c.name); // or whatever you need to do with it
}

Iterating through two lists of two inherited classes (of the same base class)

I have two lists. The types of both lists inherit from the same base type. I want to iterate through them and do operations which only use functionality of the base class without having two basically identical foreach loops one after the other.
I can't copy the lists to another list or something of the sort, as I need to use the lists in their original form separately after the operation is complete.
Is there a way to do this without writing a function?
class Program
{
static void Main(string[] args)
{
// I have two lists of inherited classes
List<Babby1> list1 = returnBabby1();
List<Babby2> list2 = returnBabby2();
// I want to iterate through both, and do the same thing, which is a part
// of the base class functionality.
// Basically I want this to be a single foreach loop.
foreach (Babby1 item in list1)
item.var = 50;
foreach (Babby2 item in list2)
item.var = 50;
// I have to send them as separate lists, the type being the original (inherited) class
sendBabby1(list1);
sendBabby2(list2);
}
static void sendBabby1(List<Babby1> list)
{
}
static void sendBabby2(List<Babby2> list)
{
}
static List<Babby1> returnBabby1()
{
return new List<Babby1>();
}
static List<Babby2> returnBabby2()
{
return new List<Babby2>();
}
}
class Base
{
public int var;
}
class Babby1 : Base
{
public int var1;
}
class Babby2 : Base
{
public int var2;
}
This should do the trick...
foreach (var item in list1.Concat<Base>(list2))
{
// Do your thing
}
EDIT: I changed Union to Concat as I think that it's probably more appropriate.
Just use the base class, like this:
List<Babby> list = new List<Base>();
list.AddRange(returnBabby1());
list.AddRange(returnBabby2());
foreach (Base item in list)
item.var = 50;
sendBabby1(list.OfType<Babby1>().ToList());
sendBabby2(list.OfType<Babby2>().ToList());
(This of course assume you have the variable you set declared in the base class)
You can use the covariance of IEnumerable<T> in order to achieve this, if you plan to simply iterate the lists and not add items or perform other operations on the list:
static SendBaby(IEnumerable<Base> list)
{
...
}
...
SendBaby(list1)
SendBaby(list2)
You can use a for loop, using Count instead. (If comparisons do consume additional CPU cycles.)
for(int i=0;i<baby1.Count||i<baby2.Count;i++)
{
if(baby1.Count<i)
baby1[i].field = 50;
if(baby2.Count<i)
baby2[i].field = 50;
}
This does it pretty well :
var babies1 = new List<Baby1>(5);
for (int i = 0; i < 5; i++)
{
babies1.Add(new Baby1 { Name = "Babies1 " + i, Var1 = 1});
}
var babies2 = new List<Baby2>(5);
for (int i = 0; i < 5; i++)
{
babies2.Add(new Baby2 { Name = "Babies2 " + i });
}
foreach (Baby b in babies1.Union<Baby>(babies2))
{
b.Var1 = 50;
}
foreach (var baby2 in babies2)
{
Console.WriteLine(baby2.Var1);
}
foreach (var baby1 in babies1)
{
Console.WriteLine(baby1.Var1);
}

Variable initalisation in while loop

I have a function that reads a file in chunks.
public static DataObject ReadNextFile(){ ...}
And dataobject looks like this:
public DataObject
{
public string Category { get; set; }
// And other members ...
}
What I want to do is the following basically
List<DataObject> dataObjects = new List<DataObject>();
while(ReadNextFile().Category == "category")
{
dataObjects.Add(^^^^^ the thingy in the while);
}
I know it's probably not how it's done, because how do I access the object I've just read.
I think what you're looking for is:
List<DataObject> dataObjects = new List<DataObject>();
DataObject nextObject;
while((nextObject = ReadNextFile()).Category == "category")
{
dataObjects.Add(nextObject);
}
But I wouldn't do that. I'd write:
List<DataObject> dataObject = source.ReadItems()
.TakeWhile(x => x.Category == "Category")
.ToList();
where ReadItems() was a method returning an IEnumerable<DataObject>, reading and yielding one item at a time. You may well want to implement it with an iterator block (yield return etc).
This is assuming you really want to stop reading as soon as you find the first object which has a different category. If you actually want to include all the matching DataObjects,
change TakeWhile to Where in the above LINQ query.
(EDIT: Saeed has since deleted his objections to the answer, but I guess I might as well leave the example up...)
EDIT: Proof that this will work, as Saeed doesn't seem to believe me:
using System;
using System.Collections.Generic;
public class DataObject
{
public string Category { get; set; }
public int Id { get; set; }
}
class Test
{
static int count = 0;
static DataObject ReadNextFile()
{
count++;
return new DataObject
{
Category = count <= 5 ? "yes" : "no",
Id = count
};
}
static void Main()
{
List<DataObject> dataObjects = new List<DataObject>();
DataObject nextObject;
while((nextObject = ReadNextFile()).Category == "yes")
{
dataObjects.Add(nextObject);
}
foreach (DataObject x in dataObjects)
{
Console.WriteLine("{0}: {1}", x.Id, x.Category);
}
}
}
Output:
1: yes
2: yes
3: yes
4: yes
5: yes
In other words, the list has retained references to the 5 distinct objects which have been returned from ReadNextFile.
This is subjective, but I hate this pattern (and I fully recognize that I am in the very small minority here). Here is how I do it when I need something like this.
var dataObjects = new List<DataObject>();
while(true) {
DataObject obj = ReadNextFile();
if(obj.Category != "category") {
break;
}
dataObjects.Add(obj);
}
But these days, it is better to say
List<DataObject> dataObjects = GetItemsFromFile(path)
.TakeWhile(x => x.Category == "category")
.ToList();
Here, of course, GetItemsFromFile reads the items from the file pointed to by path and returns an IEnumerable<DataObject>.
List<DataObject> dataObjects = new List<DataObject>();
string category = "";
while((category=ReadNextFile().Category) == "category")
{
dataObjects.Add(new DataObject{Category = category});
}
And if you have more complicated object you can do this (like jon):
List<DataObject> dataObjects = new List<DataObject>();
var category = new DataObject();
while((category=ReadNextFile()).Category == "category")
{
dataObjects.Add(category);
}
You should look into implementing IEnumerator on the class container the call to ReadNextFile(). Then you would always have reference to the current object with IEnumerator.Current, and MoveNext() will return the bool you are looking for to check for advancement. Something like this:
public class ObjectReader : IEnumerator<DataObject>
{
public bool MoveNext()
{
// try to read next file, return false if you can't
// if you can, set the Current to the returned DataObject
}
public DataObject Current
{
get;
private set;
}
}

c# generic list merge

Way I could not merge List and List? OOP says MyType2 is MyType...
using System;
using System.Collections.Generic;
namespace two_list_merge
{
public class MyType
{
private int _attr1 = 0;
public MyType(int i)
{
Attr1 = i;
}
public int Attr1
{
get { return _attr1; }
set { _attr1 = value; }
}
}
public class MyType2 : MyType
{
private int _attr2 = 0;
public MyType2(int i, int j)
: base(i)
{
Attr2 = j;
}
public int Attr2
{
get { return _attr2; }
set { _attr2 = value; }
}
}
class MainClass
{
public static void Main(string[] args)
{
int count = 5;
List<MyType> list1 = new List<MyType>();
for(int i = 0; i < count; i++)
{
list1[i] = new MyType(i);
}
List<MyType2> list2 = new List<MyType2>();
for(int i = 0; i < count; i++)
{
list1[i] = new MyType2(i, i*2);
}
list1.AddRange((List<MyType>)list2);
}
}
}
I'm going to assume that you're not using C# 4.0.
In earlier versions of C#, this won't work because the language doesn't support contravariance and covariance of generic types.
Don't worry about the academic jargon - they're just the terms for the kinds of variance (i.e. variation) permitted.
Here's a good article on the details:
http://blogs.msdn.com/b/csharpfaq/archive/2010/02/16/covariance-and-contravariance-faq.aspx
To make your code work, write this:
list1.AddRange(list2.Cast<MyType>());
If you're using C#4 (.NET 4), you can simply remove the cast in your last line:
list1.AddRange(list2);
If you're using C#3 (.NET 3.5), you need to using the Cast() LINQ extension:
list1.AddRange(list2.Cast<MyType>());
The reason that you can't cast list2 to List is that List is not covariant. You can find a good explanation of why this is not the case here:
In C#, why can't a List<string> object be stored in a List<object> variable
The reason the first line works is that AddRange() takes an IEnumerable and IEnumerable is covariant. .NET 3.5 does not implement covariance of generic collections and hence the need for the Cast() in C#3.
Perhaps try using LINQ if you can, along with an explicit cast to MyType. Using C# 4.
List<MyType> list1 = new List<MyType>
{ new MyType(1), new MyType(2), new MyType(3)};
List<MyType2> list2 = new List<MyType2>
{ new MyType2(11,123), new MyType2(22,456), new MyType2(33, 789) };
var combined = list1.Concat(list2.AsEnumerable<MyType>());

Categories

Resources