Hello there :) I'm having a problem when cloning an object that contains other objects and lists in winForm. I want to Clone an Object of Type Structure the classes are provided below first of all i have tried Shallow Clone
public Structure Clone()
{
return this.MemberwiseClone() as Structure;
}
put it didn't work so i searched https://stackoverflow.com/ and i did a deep clone
Deep cloning objects and this How do you do a deep copy of an object in .NET (C# specifically)?
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);
}
}
The Problem that I'm having is i am taking a backup copy of an object
var backup=DeepClone<Structure>(this.sched); //sched is Structure Object
and then changing this.sched
the backup is changed :(
the structre of my classes is:
[Serializable]
public class Sub
{
string name;
int studentsNumber;
int unassaignedStudent;
public Sub(string name, int number)
{
this.name = name;
this.studentsNumber = number;
this.unassaignedStudent = number;
}
public Subject()
{
this.name = "";
this.studentsNumber = 0;
this.unassaignedStudent = 0;
}
public bool Assigne(int count)
{
//stuff
}
public Sub Clone()
{
return this.MemberwiseClone() as Sub;
}
}
[Serializable]
class Room
{
string name;
int studentsNumber;
int full;
private int freeSeats;
List<Sub> subjects;
/// <summary>
/// the list of subjects
/// </summary>
internal List<Sub> Subjects
{
get { return subjects; }
set { subjects = value; }
}
Dictionary<Subject, int> variations;
public Room(string name, int number)
{
this.name = name;
this.studentsNumber = number;
this.full = 0;
this.subjects = new List<Subject>();
this.variations = new Dictionary<Subject, int>();
this.freeSeats = number;
}
public Room(int number)
{
this.studentsNumber = number;
this.full = 0;
this.subjects = new List<Subject>();
this.variations = new Dictionary<Subject, int>();
this.freeSeats = number;
}
public Room()
{
this.name = "R" + count.ToString();
count++;
this.studentsNumber = 0;
this.full = 0;
this.subjects = new List<Sub>();
this.variation= new Dictionary<Sub, int>();
this.freeSeats = 0;
}
public bool addSubject(Sub sbj)
{
//also stuff
}
public bool addPartialSubject(Sub sbj)
{
//stuff
// return false;
}
public Room Clone()
{
return this.MemberwiseClone() as Room;
}
}
[Serializable]
class Period
{
List<Room> rooms;
int conflicts;
List<Sub> subjects;
internal List<Sub> Subjects
{
get { return subjects; }
set { subjects = value; }
}
/// <summary>
/// Create an instance of class Period
/// </summary>
/// <param name="rooms">the rooms in this Period</param>
public Period(List<Room> rooms)
{
this.conflicts = 0;
this.rooms = rooms;
subjects = new List<Subject>();
fillSubjects(ref rooms, ref subjects);
}
public Period()
{
this.conflicts = 0;
this.rooms = null;
subjects = new List<Subt>();
freeSeats = 0;
}
/// <summary>
/// Fill the subjects in the rooms to the list of subjects
/// </summary>
/// <param name="rooms">referance to the list of the rooms</param>
/// <param name="subjects">referance to the list of the subjects</param>
private void fillSubjects(ref List<Room> rooms, ref List<Sub> subjects)
{
foreach (var room in rooms)
{
foreach (var subject in room.Subjects)
{
if (!subjects.Exists(s => s.Name == subject.Name))
subjects.Add(subject);
}
}
}
/// <summary>
/// Adds the given subject to the period if there is a place in any room
/// </summary>
/// <param name="s">the subject to add</param>
/// <returns>true if there is space for this subject and added, otherwise false</returns>
public bool AddSubject(Sub s)
{
foreach (var room in rooms)
{
if (room.addSubject(s))
{
//stuff
}
else
if (room.addPartialSubject(s))
{
//stuff
}
}
return false;
}
private int CalculateConflictions(Sub s)
{
//also a lot of stuff
}
}
[Serializable]
class Structure:IDisposable
{
int days;
/// <summary>
/// the number of days in the Schedual
/// </summary>
public int Days
{
get { return days; }
set { days = value; }
}
int periods;
Period[,] schedualArray;
List<Room> rooms;
internal List<Room> Rooms
{
get { return rooms; }
set { rooms = value; }
}
/// <summary>
/// Creates an instance of the Structure object
/// </summary>
/// <param name="rooms">a list of the rooms in the Schedual</param>
public Structure(int days, int periods,List<Room> rooms)
{
this.days = days;
this.periods = periods;
this.rooms=rooms;
this.schedualArray = new Period[days, periods];
this.subjectCount = 0;
for (int i = 0; i < days; i++)
{
for (int j = 0; j < periods; j++)
{
schedualArray[i, j] = new Period(CloneList(ref rooms)); //here i cloned the list to be in the safe side and it didn't work also
}
}
}
public Structure()
{
this.days = 0;
this.totalEval = Int32.MaxValue;
this.periods = 0;
this.rooms = null;
this.subjectCount = 0;
this.schedualArray = null;
}
internal bool AddSubject(Sub subject, int day, int period)
{
//add the subject into inner lists (room)
}
public void PrintStruct()
{
for (int i = 0; i < days; i++)
{
for (int j = 0; j < periods; j++)
{
foreach (var subject in schedualArray[i, j].Subjects)
{
Console.Write("\t\t");
}
Console.Write("\t\t");
}
Console.WriteLine();
}
}
public Structure Clone()
{
return this.MemberwiseClone() as Structure;
}
public List<Room> CloneList(ref List<Room> rooms)
{
var lst = new List<Room>();
foreach (var room in rooms)
{
lst.Add(DeepClone<Room>(room));
}
return lst;
}
internal void RemoveSubject(Sub subject)
{
//..................
}
#region IDisposable Members
public void Dispose()
{
GC.Collect(g, GCCollectionMode.Forced);
}
#endregion
}
I don't really now what are the details of the cloning process but my requirement is to clone the entire object with the successive objects in the structure and hirarachy of the object and the complete items that the list points to not only there references Please Can anyone help me please I'm really lost:(, thanks in advance to everyone interested in helping me :) Yaser
EDIT when using the method @WiiMaxx
Structure backup=XamlClone(this.sched);
private Structure XamlClone(Structure s)
{
//First Step
// create a XAML string
string stCopie = XamlWriter.Save(s);
//Secound Step
// convert him back to an Object of YourTyp
return XamlReader.Load(XmlReader.Create(new StringReader(stCopie))) as Structure;
}
but the inner period[,]
is cloned as null
Can you please help me @WiiMaxx
Edit 2.0
i have also checked this article about deep cloning in 3 methods and i think i have circular references in my code that is why this isn't working for me
http://blog.nuclex-games.com/mono-dotnet/fast-deep-cloning/
End Edit