有没有办法将类字段标记为仅反序列化而不是序列化?

时间:2010-02-05 16:29:16

标签: c# .net serialization

这听起来很奇怪,但这正是我想要的,因为我正在使用一个名为“Project”的数据结构,它被序列化为一个保存文件。我希望能够使用已弃用的字段对旧版本的保存文件进行反序列化,然后仅使用当前使用的字段对其进行重新序列化。问题是我想在重新序列化结构时删除那些已弃用的字段,以便最小化文件大小。是否可以将字段标记为“仅可反序列化”?

修改

感谢您的想法!我决定主要根据NickLarsen的建议构建并创建项目结构的旧版本,并在单独的命名空间中包含所有折旧字段。不同之处在于我决定在反序列化时执行升级。这很棒,因为我可以在一行中完成所有工作(希望你能得到我在这里所做的一切):

Project myProject = new Project((Depreciated.Project)myFormatter.Deserialize(myStream));

构造函数只是根据旧的膨胀数据结构返回一个新的最小数据结构实例。

第二次修改:

我决定遵循bebop的建议,为每个项目版本创建新的类,包括所有折旧和新字段。然后每个项目的构造函数升级到下一个版本,一路上除去折旧字段。以下是从版本1.0.0转换的说明性示例 - > 1.0.5 - >电流。

Project myProject = new Project(new Project105((Project100)myFormatter.Deserialize(myStream)));

这样做的一个关键是使用SerializationBinder将反序列化的文件以及任何字段强制转换为旧版本的类。

5 个答案:

答案 0 :(得分:1)

每次结构更改时都不能创建数据结构类的新版本,并让新类的构造函数获取前一个类的实例,并从那里填充自己。要加载最新的类,您尝试从序列化文件创建最早的类,直到成功,然后重复将其传递到链中下一个类的构造函数,直到获得最新版本的数据结构,然后您可以保存

为每种格式更改设置一个新类可以避免在数据结构发生变化时更改任何现有代码,并且您的应用可能不知道保存文件是某些旧版本的事实。它允许您从任何以前的版本加载,而不仅仅是最后一个版本。

chain of responsibility实现的这类内容可以轻松插入新格式,只需对现有代码进行最少的更改。

虽然不是教科书的责任链,但你可以通过以下方式实施:

(注意:未经测试的代码)

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的共同性带入基类,但它可以解决这个问题。

答案 1 :(得分:1)

你有几个选择。

首先,您可以为旧格式创建类的版本(可能在不同的命名空间中),并为新格式创建一个版本。在旧类中,重载serialize函数以抛出错误,或将自身转换为新类并将其序列化。

其次,您可以编写自己的序列化程序,这将涉及更多。有plenty of resources可以帮助你。

答案 2 :(得分:0)

据我所知,.NET非常小心,只能序列化它可以反序列化的东西,反之亦然。

答案 3 :(得分:0)

没有定义明确支持的属性,但可能的一种可能性是使用ISerializable定义自定义序列化,或者为您的类型定义自定义序列化程序类,在序列化时不执行任何操作

答案 4 :(得分:0)

我认为你要搜索的是OptionalFieldAttribute