【问题标题】:How to serialize a class that may only have unique instances如何序列化可能只有唯一实例的类
【发布时间】:2018-07-22 16:32:31
【问题描述】:

我有一个类只能有如下的唯一实例。这使得引用相等足以等同于对象。

虽然序列化很简单,但反序列化有点棘手,因为不能像我在下面所做的那样分配给this。如果仍然只想维护类的唯一实例,我该如何反序列化对象?

public sealed class MyClass :
    ISerializable,
    IXmlSerializable
{
    private static readonly Dictionary<string, MyClass> Cache;

    static MyClass() { /* build cache, use private constructor */ }

    private MyClass(string name)
    {
        this.Name = name;
    }

    public string Name { get; }

    public static MyClass Parse(string from)
        => Cache[from];

    public void GetObjectData(SerializationInfo info, StreamingContext context)
        => throw new NotImplementedException();

    public XmlSchema GetSchema() => null;

    public void ReadXml(XmlReader reader)
    {
        reader.ReadStartElement();
        this = Parse(reader.ReadContentAsString());
        reader.ReadEndElement();
    }

    public MyClass(SerializationInfo info, StreamingContext context) 
        => this = Parse(info.GetString(nameof(this.Name)));

    public void WriteXml(XmlWriter writer)
        => throw new NotImplementedException();
}

【问题讨论】:

  • 如果您能够更改您的课程代码,我强烈建议您将您的课程替换为三个不同的课程;一个用于序列化/反序列化,一个用于缓存,另一个用于您需要缓存的类。您的班级在这里承担不同的职责,这使其更加复杂。

标签: c# serialization


【解决方案1】:

一般来说,处理这个问题的方法是,在对象图序列化过程中,使用serialization surrogate mechanism 替换单例,其中单例替换为Data Transfer Object (DTO),它只包含标识符对于单身人士。然后,稍后,随着图形被反序列化,DTO 最初被反序列化,然后通过查找替换为相应的单例。

例如,如果您的 MyClass 如下所示:

public sealed class MyClass
{
    private static readonly Dictionary<string, MyClass> Cache;

    static MyClass()
    {
        Cache = new Dictionary<string, MyClass>()
        {
            { "one", new MyClass("one") { OtherRuntimeData = "other runtime data 1" } },
            { "two", new MyClass("two") { OtherRuntimeData = "other runtime data 2" } },
        };
    }

    // XmlSerializer required parameterless constructor.
    private MyClass() => throw new NotImplementedException();

    private MyClass(string name) => this.Name = name;

    public string Name { get; }

    public string OtherRuntimeData { get; set; }

    public static MyClass Parse(string from) => Cache[from];

    public static IEnumerable<MyClass> Instances => Cache.Values;
}

然后一个只包含 Name 的 DTO 看起来像:

public sealed class MyClassDTO
{
    public string Name { get; set; }

    public static implicit operator MyClassDTO(MyClass obj) => obj == null ? null : new MyClassDTO { Name = obj.Name };

    public static implicit operator MyClass(MyClassDTO dto) => dto == null ? null : MyClass.Parse(dto.Name);
}

注意implicit operator 用于在 DTO 和原始文件之间进行转换?这样可以更轻松地将代理项注入序列化图中。

不幸的是,在所有常用的 .Net 序列化程序中,没有标准的方法来实现序列化代理 DTO 的注入。每个都有自己独立的机制(或根本没有机制)。分解它们:

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-09-24
    • 2016-08-30
    • 1970-01-01
    • 1970-01-01
    • 2012-02-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多