не могли бы вы не создавать новую версию вашего класса структуры данных каждый раз, когда структура изменяется, и чтобы конструктор для нового класса взял экземпляр предыдущего класса и заполнил себя оттуда. Чтобы загрузить самый новый класс, вы пытаетесь создать самый ранний класс из сериализованного файла до тех пор, пока он не будет успешно выполнен, а затем несколько раз передавать его в конструктор следующего класса в цепочке, пока не получите последнюю версию структуры данных, затем вы можете сохранить ее .
Наличие нового класса для каждого изменения формата позволит избежать необходимости изменять какой-либо существующий код при изменении структуры данных, и ваше приложение может не знать о том, что файл сохранения был какой-то более старой версией. Это позволит вам загружать из любой предыдущей версии, а не только из последней.
Подобные вещи, реализуемые цепочкой ответственности , могут упростить переход на новый формат с минимальными изменениями в существующем коде.
Хотя цепочка ответственности в учебниках не реализована, вы можете реализовать что-то вроде этого:
(ПРИМЕЧАНИЕ: непроверенный код)
public interface IProductFactory<T> where T : class
{
T CreateProduct(string filename);
T DeserializeInstance(string filename);
}
public abstract class ProductFactoryBase<T> : IProductFactory<T> where T : class
{
public abstract T CreateProduct(string filename);
public T DeserializeInstance(string filename)
{
var myFormatter = new BinaryFormatter();
using (FileStream stream = File.Open(filename, FileMode.Open))
{
return myFormatter.Deserialize(stream) as T;
}
}
}
public class ProductV1Factory : ProductFactoryBase<ProductV1>
{
public override ProductV1 CreateProduct(string filename)
{
return DeserializeInstance(filename);
}
}
public class ProductV2Factory : ProductFactoryBase<ProductV2>
{
ProductV1Factory successor = new ProductV1Factory();
public override ProductV2 CreateProduct(string filename)
{
var product = DeserializeInstance(filename);
if (product==null)
{
product = new ProductV2(successor.CreateProduct(filename));
}
return product;
}
}
public class ProductV2
{
public ProductV2(ProductV1 product)
{
//construct from V1 information
}
}
public class ProductV1
{
}
это имеет то преимущество, что когда вы хотите добавить ProductV3, вам нужно всего лишь изменить класс, который вы используете в своем приложении, на тип ProductV3, что вам нужно сделать в любом случае, а затем изменить код загрузки, чтобы он использовал ProductV3Factory, который в основном совпадает с ProductV2Factory, но использует в качестве преемника ProductV2Factory. Вам не нужно менять какие-либо существующие классы. Вы, вероятно, могли бы немного реорганизовать это, чтобы ввести в базовый класс обычную комбинацию CreateProduct
, но это дает представление.