C# 如何序列化可能只有唯一实例的类
我有一个类,它只能有唯一的实例,如下所示。这使得引用相等足以等同于对象 虽然序列化很简单,但反序列化有点棘手,因为不能像我在下面所做的那样分配给C# 如何序列化可能只有唯一实例的类,c#,serialization,C#,Serialization,我有一个类,它只能有唯一的实例,如下所示。这使得引用相等足以等同于对象 虽然序列化很简单,但反序列化有点棘手,因为不能像我在下面所做的那样分配给这个。如果仍然希望只维护类的唯一实例,如何反序列化对象 public sealed class MyClass : ISerializable, IXmlSerializable { private static readonly Dictionary<string, MyClass> Cache; stat
这个
。如果仍然希望只维护类的唯一实例,如何反序列化对象
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();
}
公共密封类MyClass:
ISerializable,
IXmlSerializable
{
私有静态只读字典缓存;
静态MyClass(){/*构建缓存,使用私有构造函数*/}
私有MyClass(字符串名称)
{
this.Name=Name;
}
公共字符串名称{get;}
公共静态MyClass解析(来自的字符串)
=>缓存[从];
public void GetObjectData(SerializationInfo信息、StreamingContext上下文)
=>抛出新的NotImplementedException();
公共XmlSchema GetSchema()=>null;
公共void ReadXml(XmlReader)
{
reader.ReadStartElement();
this=Parse(reader.ReadContentAsString());
reader.ReadEndElement();
}
公共MyClass(SerializationInfo信息、StreamingContext上下文)
=>this=Parse(info.GetString(nameof(this.Name));
public void WriteXml(XmlWriter)
=>抛出新的NotImplementedException();
}
一般来说,处理此问题的方法是,在对象图序列化期间,使用替换单例,其中将单例替换为只包含单例标识符的。然后,稍后,当图形被反序列化时,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;
}
public class RootObject
{
// Technique taken from https://stackoverflow.com/questions/3280362/most-elegant-xml-serialization-of-color-structure
[XmlElement(Type=typeof(MyClassDTO))]
public MyClass MyClass { get; set; }
}
注意在DTO和原始之间进行转换的方法?这将使将代理注入序列化图变得更容易
然而,不幸的是,在所有常用的.Net序列化程序中,都没有实现序列化代理DTO注入的标准方法。每个都有自己的独立机制(或者根本没有机制)。要分解它们:
- 数据协定序列化程序支持通过接口使用代理进行替换,如to或to中所示
- 数据协定序列化程序还支持到中所示的接口
- 但不幸的是,
不支持通过代理机制注入DTO。最接近的方法是技巧from to,它涉及为引用单例类型的每个属性设置to DTO类型,例如:XmlSerializer
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; }
在此处显示此操作的.Net小提琴示例:。注意,这只是因为我们前面定义的singleton和它的DTO之间的隐式运算符才起作用public class RootObject { // Technique taken from https://stackoverflow.com/questions/3280362/most-elegant-xml-serialization-of-color-structure [XmlElement(Type=typeof(MyClassDTO))] public MyClass MyClass { get; set; } }
- 当通过Json.NET序列化时,单例可以替换为其内部的DTO
- 支持通过
替换代理项,如中所示,或文章中所示RuntimeTypeModel.Default.Add(typeof(OriginalType),false)、seturrogate(typeof(代理类型))
- 最后,如果您使用的是
(出于解释的原因,我不建议使用),则支持使用类似于数据契约代理替换机制的机制,如中所示BinaryFormatter
还支持与SerializationInfo.SetType()
组合使用,如中所示IObjectReference