Reputation: 98
I need to make a copy of a MyGame class and use it in my simulation for game trials before I select a move to play.
For example :
public class MyGame
{
private int Start;
private Board board;
//Constructor
public void Play()
{
//play game
}
public object Clone()
{
}
}
public class Board
{
private int Count;
//Constructor
//Some methods and properties
public object Clone()
{
}
}
Writing code for the method Clone() I have tried
I have read alot of articles and forums about this topic. The answer most people use is Deep cloning objects in C#, I tried samples with respect to my project but I still get my simulation modifying the original object (MyGame Class) and not the copy.
Upvotes: 0
Views: 5715
Reputation: 12521
Here I have an example for a deep copy, which deeply copies all reference type objects that are used with a copy constructor:
public sealed class MyGame
{
private int start;
private Board board;
public MyGame(MyGame orig)
{
// value types - like integers - can easily be
// reused
this.start = orig.start;
// reference types must be clones seperately, you
// must not use orig.board directly here
this.board = new Board(orig.board);
}
}
public sealed class Board
{
private int count;
public Board(Board orig)
{
// here we have a value type again
this.count = orig.count;
// here we have no reference types. if we did
// we'd have to clone them too, as above
}
}
I think your copy might be somehow shallow and re-use some references (like for instance this.board = orig.board
instead of creating a new board). This is a guess though, as I can't see your cloning implementation.
Furthermore, I used copy constructors instead of implementing ICloneable
. The implementation is almost the same. One advantage though is that you simplify dealing with subclasses:
Suppose you had a MyAwesomeGame : MyGame
, not overriding MyGame.Clone
. What would you get from myAwesomeGame.Clone()
? Actually, still a new MyGame
because MyGame.Clone
is the method in charge. One may carelessly expect a properly cloned MyAwesomeGame
here, however. new MyGame(myAwesomeGame)
still copies somehow incompletely, but it's more obvious. In my example I made the classes sealed
to avoid this failures. If you can seal them, there's good change it will make your life simpler.
Implementing ICloneable
is not recommended in general, see Why should I implement ICloneable in c#? for more detailed and general information.
Here I have an ICloneable
approach anyway, to make things complete and enable you to compare and contrast:
public class MyGame : ICloneable
{
private int start;
private Board board;
public object Clone()
{
var copy = new MyGame();
copy.start = this.start;
copy.board = (Board)this.board.Clone();
return copy;
}
}
public class Board : ICloneable
{
private int count;
public object Clone()
{
var copy = new Board();
copy.count = this.count;
return copy;
}
}
Upvotes: 4
Reputation: 1366
I have two extension methods that I use to achieve this. Demo code below:
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
namespace SimpleCloneDemo
{
public class Program
{
public static void Main(string[] args)
{
var person = new Person { Id = 1, FirstName = "John", Surname = "Doe" };
var clone = person.Clone();
clone.Id = 5;
clone.FirstName = "Jane";
Console.WriteLine(@"person: {0}", person);
Console.WriteLine(@"clone: {0}", clone);
if (Debugger.IsAttached)
Console.ReadLine();
}
}
public class Person
{
public int Id { get; set; }
public string FirstName { get; set; }
public string Surname { get; set; }
public override string ToString()
{
return string.Format("Id: {0}, Full Name: {1}, {2}", Id, Surname, FirstName);
}
}
public static class ObjectExtensions
{
public static T Clone<T>(this T entity) where T : class
{
var clone = Activator.CreateInstance(entity.GetType());
var entityPropValueDictionary = entity.AsPropValueDictionary();
foreach (var prop in clone.GetType().GetProperties())
{
clone.GetType().GetProperty(prop.Name).SetValue(clone, entityPropValueDictionary[prop.Name]);
}
return clone as T;
}
public static IDictionary<string, object> AsPropValueDictionary<T>(this T instance, params BindingFlags[] bindingFlags)
{
var runtimeBindingFlags = BindingFlags.Default;
switch (bindingFlags.Count())
{
case 0:
runtimeBindingFlags = BindingFlags.Default;
break;
case 1:
runtimeBindingFlags = bindingFlags[0];
break;
default:
runtimeBindingFlags = bindingFlags.Aggregate(runtimeBindingFlags, (current, bindingFlag) => current | bindingFlag);
break;
}
return runtimeBindingFlags == BindingFlags.Default
? instance.GetType().GetProperties().ToDictionary(prop => prop.Name, prop => prop.GetValue(instance))
: instance.GetType().GetProperties(runtimeBindingFlags).ToDictionary(prop => prop.Name, prop => prop.GetValue(instance));
}
}
}
Result:
I wrote these quick-and-dirty extension methods in a hurry so there are probably some issues with it and they are probably horribly inefficient, but they seemed to work for my use case. They may help you, too.
Upvotes: 0
Reputation: 67148
MemberwiseClone()
creates a stupid shallow clone of each member of an object. This works fine when members are value types but in case of reference types it fails because it'll clone pointers and not pointed objects.
Starting from your code a memberwise clone is something like this:
public object Clone()
{
MyGame cloned = new MyGame();
cloned.Start = this.Start; // Copied (cloned) because value type
cloned.Board = this.Board; // This is not a copy, just a reference!
}
A better solution for a deep clone would be to implement ICloneable
(for example, otherwise a copy constructor approach is also good) for each reference type, let's suppose Board
is cloneable too:
public object Clone()
{
MyGame cloned = new MyGame();
cloned.Start = this.Start;
cloned.Board = (Board)this.Board.Clone();
}
Please note that in your example Board
can implement Clone()
using MemberwiseClone()
because its members are all value types.
If you can't manage this (for example because code is not accesible) or you need a quick/dirty solution you may consider to user serializaiton (in memory). Which serializer is a big question, each one has some limitations (about what's serialized and how). For example XML serializer won't serialize private fields (it won't serialize fields at all). Faster one is binary formatter but you need to mark each class with a proper attribute.
Change according serializer you prefer (according to your requirements), in this case I assume you marked MyGame
and Board
as [Serializable]
for the quick binary serialization:
public object Clone()
{
using (var stream = new MemoryStream())
{
var formatter = new BinaryFormatter();
formatter.Serialize(stream, this);
stream.Seek(0, SeekOrigin.Begin);
return formatter.Deserialize(stream);
}
}
Upvotes: 1
Reputation: 17657
Try this
public static T DeepCopy<T>(this T obj)
{
T result;
var serializer = new DataContractSerializer(typeof(T));
using (var ms = new MemoryStream())
{
serializer.WriteObject(ms, obj);
ms.Position = 0;
result = (T)serializer.ReadObject(ms);
ms.Close();
}
return result;
}
Upvotes: 0
Reputation: 14332
The simplest and most reliable way to implement deep cloning is to serialize, and then deserialize your objects. This can have a large performance cost associated with it. Consider classes from this namespace for serialization http://msdn.microsoft.com/en-us/library/System.Xml.Serialization.aspx
Deep cloning requires recursively creating a new instance of every property that is not a value type. Cloning MyGame
would require a new instance of MyGame
and a new instance of Board
, both populated with the same Start
and Count
values as their originals. This is fiddly and a nightmare to maintain. As you can guess, it is not an automatic process out of the box but it can be, using reflection (which is how the xml serialization above works.
MemberwiseClone
only creates a new instance of the object you called it on - all references remain the same.
Upvotes: 1