Tworzymy sobie interfejs który pomoże nam zwracać konkretny typ obiektu na nie zwykłe object.
namespace System {
/// <summary>
/// Supports cloning, which creates a new instance of a class with the same value
/// as an existing instance.
/// </summary>
/// <typeparam name="T"></typeparam>
public interface ICloneable<T> : ICloneable {
/// <summary>
/// Creates a new object that is a copy of the current instance.
/// </summary>
/// <returns>A new object that is a copy of this instance.</returns>
new T Clone();
}
}
Teraz implementujemy nasz interfejs w klasie, którą ma być klonowalna. Klasa taka powinna być oznaczona atrybutem [Serializable], ponieważ całe to klonowanie oparte jest na serializacji.
[Serializable]
public sealed class MyClass: ICloneable<MyClass> {
// ... jakieś właściwości, metody itd.
#region ICloneable Members
/// <summary>
/// Creates a new object that is a copy of the current instance.
/// </summary>
/// <returns>
/// A new object that is a copy of this instance.
/// </returns>
object ICloneable.Clone() {
using (var ms = new System.IO.MemoryStream()) {
var bf = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter(null,
new System.Runtime.Serialization.StreamingContext(
System.Runtime.Serialization.StreamingContextStates.Clone));
bf.Serialize(ms, this);
ms.Seek(0, System.IO.SeekOrigin.Begin);
return bf.Deserialize(ms);
}
}
#endregion
#region ICloneable<MyClass> Members
/// <summary>
/// Clones this instance.
/// </summary>
/// <returns></returns>
public MyClass Clone() {
return (this as ICloneable).Clone() as MyClass;
}
#endregion
}
Trzeba pamiętać że wszystkie właściwości, które są obiektami złożonymi muszą się dać zserializować.
Teraz można wykorzystać naszą klasę:
var myClass = new MyClass();
// ... coś tam
var clone = myClass.Clone();
To wszystko, Oczywiście można by zrobić klonowanie z wykorzystaniem this.MemberwiseClone() ale taka kopia jest płytka ... czyli typy referencyjne nie są klonowane