Mam w swoim programie klasę Store, która jest dość rozbudowana - zawiera zarówno pola typów wartościowych, jak i innych klas, które z kolei znowu składają się z pól wartościowych i referencyjnych... Takie "drzewko" jest dość duże i ma jak na razie 5 poziomów zagnieżdżenia.
Potrzebuję w programie utworzyć kopię obiektu mojej klasy głównej i zachować ją w pamięci, aby następnie móc ją porównać z innym obiektem tej klasy.
Wobec tego postanowiłem zaimplementować metody Object.Equals i ICloneable.Clone. Ale chciałbym, żeby było to po pierwsze sprawne, po drugie łatwe do rozbudowywania.
Ręczna implementacja tych metod będzie czasochłonna, bo musiałbym to zrobić nie tylko w klasie głównej, ale i we wszystkich, z którymi jest powiązana, a jest ich już sporo. Do tego będą pojawiały się nowe, a w już istniejących na pewno będą pojawiały się nowe pola. Każda taka zmiana wymagałaby ingerencji w treść metod, a tego chcę uniknąć.
Wpadłem na pomysł użycia do tego serializacji binarnej, ale nie chce ona działać. Oto moja metoda kopiująca:
public object Clone()
{
using (MemoryStream ms = new MemoryStream())
{
BinaryFormatter bf = new BinaryFormatter();
bf.Serialize(ms, this);
ms.Position = 0;
return bf.Deserialize(ms);
}
}
Powinno działać, ale nie działa. Klasa Store ma trzy pola typu string i jedno typu List<Product>. O ile klonowanie dla wypełnionego obiektu działa dobrze, o tyle przy "pustym" (każdy string to "", a lista ma 0 elementów) z obiektu, który zajmuje 803 bajty tworzy kopię, która ma ich 801, więc moja metoda porównująca twierdzi, że są to różne obiekty.
Dlaczego?
Tu metoda Equals (również oparta na serializacji binarnej), na wszelki wypadek:
public override bool Equals(object obj)
{
Store second = obj as Store;
using (MemoryStream myStream = new MemoryStream(), secStream = new MemoryStream())
{
BinaryFormatter bin = new BinaryFormatter();
bin.Serialize(myStream, this);
bin.Serialize(secStream, obj);
if (myStream.Length != secStream.Length)
return false;
byte[] myBytes = myStream.ToArray();
byte[] secBytes = secStream.ToArray();
for (int i = 0; i < myBytes.Length; i++)
if (myBytes[i] != secBytes[i])
return false;
return true;
}
}
Aha - próby użycia w analogiczny sposób serializacji XML kończą się StackOverException.