📜 ⬆️ ⬇️

Deserialize to existing objects using standard formatter

Established deserialization .net always creates a graph of new objects. This is not always convenient.



The search did not give a ready answer. There are not very simple solutions using protobuf and other third-party serializers, but this is not always applicable.
')
The task as a whole is simple, and my solution is not something outstanding, but on the other hand, it will be easier for those who face a similar problem for the first time.



Serialization is done as usual. The following 2 classes will solve the problem during deserialization.

[Serializable] public class RealObjectHelper : IObjectReference, ISerializable { Object m_realObject; virtual object getObject(ObjectId id) { //     , return id.GetObject(); } public RealObjectHelper(SerializationInfo info, StreamingContext context) { ObjectId id = (ObjectId)info.GetValue("ID", typeof(ObjectId)); m_realObject = getObject(id); if(m_realObject == null) return; Type t = m_realObject.GetType(); MemberInfo[] members = FormatterServices.GetSerializableMembers(t, context); List<MemberInfo> deserializeMembers = new List<MemberInfo>(members.Length); List<object> data = new List<object>(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 RealObjectBinder: SerializationBinder { String assemVer; String typeVer; public RealObjectBinder(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(RealObjectHelper); } typeToDeserialize = Type.GetType( String.Format( "{0}, {1}", typeName, assemblyName ) ); return typeToDeserialize; } } 


When deserializing, you must install Binder, which will create a wrapper for deserialization into your existing object.

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

Source: https://habr.com/ru/post/159855/


All Articles