C#DataContract序列化,如何反序列化到已存在的实例

我有一个类,它包含所有现有实例的静态字典,这些实例是在编译时定义的。

基本上它看起来像这样:

[DataContract] class Foo { private static Dictionary instances = new Dictionary(); [DataMember] private long id; public static readonly Foo A = Create(1); public static readonly Foo B = Create(2); public static readonly Foo C = Create(3); private static Foo Create(long id) { Foo instance = new Foo(); instance.id = id; instances.Add(instance); return instance; } public static Foo Get(long id) { return instances[id]; } } 

还有其他字段,派生类,但这对问题无关紧要。

只有id被序列化。 当反序列化此类型的实例时,我想使用Foo.Get(id)而不是获取新实例来获取已创建为静态字段( ABC )的实例。

有一个简单的方法吗? 我没有找到任何我能够理解的资源。

在反序列化期间,它(AFAIK)总是使用一个新对象( FormatterServices.GetUninitializedObject ),但为了让它反序列化 (但在它们返回给调用者之前)替换对象,你可以实现IObjectReference ,如下所示:

 [DataContract] class Foo : IObjectReference { // <===== implement an extra interface object IObjectReference.GetRealObject(StreamingContext ctx) { return Get(id); } ...snip } 

完成...certificate:

 static class Program { static void Main() { Foo foo = Foo.Get(2), clone; DataContractSerializer ser = new DataContractSerializer(typeof(Foo)); using (MemoryStream ms = new MemoryStream()) { // clone it via DCS ser.WriteObject(ms, foo); ms.Position = 0; clone = (Foo)ser.ReadObject(ms); } Console.WriteLine(ReferenceEquals(foo, clone)); // true } } 

请注意,对于MSDN上的部分信任方案, 此处有一些额外的注释。

我有一个类似的问题,我发现最好的解决方案是添加一些包装类,即管理需要序列化的实例。

我不确定合同的确切签名。 我使用了SerializableAttribute,并且看起来很好看。 像那样:

 [Serializable] class FooSerializableWrapper : ISerializable { private readonly long id; public Foo Foo { get { return Foo.Get(id); } } public FooSerializableWrapper(Foo foo) { id = foo.id; } protected FooSerializableWrapper(SerializationInfo info, StreamingContext context) { id = info.GetInt64("id"); } void GetObjectData(SerializationInfo info, StreamingContext context) { info.AddValue("id", id); } } 

您可以使用OnDeserializingAttribute向您寻找所需内容。 但是,这可能只允许您设置属性(因此您可以拥有相当于使用静态实例填充当前实例的所有属性的Copy方法。

我想如果你真的想要返回你的静态实例,你可能不得不编写自己的反序列化器……

未经测试,但我认为你可以很容易地实现一个反序列化器:

 public class MyDeserializer : System.Xml.Serialization.XmlSerializer { protected override object Deserialize(System.Xml.Serialization.XmlSerializationReader reader) { Foo obj = (Foo)base.Deserialize(reader); return Foo.Get(obj.id); } } 

请注意,您必须执行一些有关获取ID的信息,因为它在您的代码中是私有的; 此外,这假设您正在使用XML序列化; 用你实际使用的任何东西替换inheritance。 最后,这意味着您在反序列化对象时必须实例化此类型,这可能涉及更改某些代码和/或配置。

没问题,只需使用2个class级。 在getObject方法中,您将获得现有对象

 [Serializable] public class McRealObjectHelper : IObjectReference, ISerializable { Object m_realObject; virtual object getObject(McObjectId id) { return id.GetObject(); } public McRealObjectHelper(SerializationInfo info, StreamingContext context) { McObjectId id = (McObjectId)info.GetValue("ID", typeof(McObjectId)); m_realObject = getObject(id); if(m_realObject == null) return; Type t = m_realObject.GetType(); MemberInfo[] members = FormatterServices.GetSerializableMembers(t, context); List deserializeMembers = new List(members.Length); List data = new List(members.Length); foreach(MemberInfo mi in members) { Type dataType = null; if(mi.MemberType == MemberTypes.Field) { FieldInfo fi = mi as FieldInfo; dataType = fi.FieldType; } else if(mi.MemberType == MemberTypes.Property){ PropertyInfo pi = mi as PropertyInfo; dataType = pi.PropertyType; } try { if(dataType != null){ data.Add(info.GetValue(mi.Name, dataType)); deserializeMembers.Add(mi); } } catch (SerializationException) { //some fiels are missing, new version, skip this fields } } FormatterServices.PopulateObjectMembers(m_realObject, deserializeMembers.ToArray(), data.ToArray()); } public object GetRealObject( StreamingContext context ) { return m_realObject; } [SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.SerializationFormatter)] public void GetObjectData(SerializationInfo info, StreamingContext context) { } } public class McRealObjectBinder: SerializationBinder { String assemVer; String typeVer; public McRealObjectBinder(String asmName, String typeName) { assemVer = asmName; typeVer = typeName; } public override Type BindToType( String assemblyName, String typeName ) { Type typeToDeserialize = null; if ( assemblyName.Equals( assemVer ) && typeName.Equals( typeVer ) ) { return typeof(McRealObjectHelper); } typeToDeserialize = Type.GetType( String.Format( "{0}, {1}", typeName, assemblyName ) ); return typeToDeserialize; } } 

然后,反序列化时:

 BinaryFormatter bf = new BinaryFormatter(null, context); bf.Binder = new McRealObjectBinder(YourType.Assembly.FullName, YourType.FullName); bf.Deserialize(memStream);