Deserialisieren Sie mit einem Standardformatierer in vorhandene Objekte

    Regelmäßige Deserialisierung .net erstellt immer ein Diagramm mit neuen Objekten. Dies ist nicht immer bequem.

    • Wenn Objekte beispielsweise nicht serialisierbare Daten enthalten, öffnen Sie Handles und mehr.
    • Objekte, die nicht in die Serialisierung fallen, können Verknüpfungen zu zu lesenden Objekten usw. aufweisen. Dies gilt insbesondere dann, wenn Ihre Baugruppe von einer anderen Person verwendet wird und Sie nicht alle Fälle mit dem richtigen Design lösen können.
    • Und am Ende ist es irrational, Objekte vollständig neu zu erstellen, um ein kleines Undo zu erzielen.


    Die Suche ergab keine fertige Antwort. Es gibt nicht die einfachsten Lösungen für die Verwendung von Protobuf und anderen Serialisierern von Drittanbietern, dies ist jedoch nicht immer möglich.

    Die Aufgabe insgesamt ist nicht schwierig, und meine Lösung ist nicht herausragend, aber für diejenigen, die zum ersten Mal mit einem ähnlichen Problem konfrontiert sind, wird es einfacher sein.



    Die Serialisierung erfolgt wie gewohnt. Die folgenden 2 Klassen lösen das Problem der Deserialisierung.

    	
    	[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 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 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;
    		}
    	}
    

    При десериализации надо установить Binder, который создаст обертку для десериализации в ваш существующий объект.

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

    Jetzt auch beliebt: