Is it possible to do .NET binary serialization of an object when you don't have the source code of the class?

后端 未结 6 1117
星月不相逢
星月不相逢 2020-11-27 04:52

I am using BinaryFormatter to do binary serialization of some objects in C#. However, some of the objects contain classes that I access via a DLL and do not hav

6条回答
  •  囚心锁ツ
    2020-11-27 04:55

    You could create a serialization surrogate.

    Imagine that we have a class defined in a referenced assembly that we have no control over that looks like this:

    public class Person
    {
        public string Name { get; set; }
        public int Age { get; set; }
        public DriversLicense License;
    }
    
    
    // An instance of this type will be part of the object graph and will need to be 
    // serialized also.
    public class DriversLicense
    {
        public string Number { get; set; }
    }
    

    In order to serialize this object you will need to define a serialization surrogate for each type in the object graph.

    To create a serialization surrogate you simply need to create a type that implements the ISerializationSurrogate interface:

    public class PersonSurrogate : ISerializationSurrogate
    {
        /// 
        /// Manually add objects to the  store.
        /// 
        public void GetObjectData(object obj, SerializationInfo info, StreamingContext context)
        {
            Person person = (Person) obj;
            info.AddValue("Name", person.Name);
            info.AddValue("Age", person.Age);
            info.AddValue("License", person.License);
        }
    
        /// 
        /// Retrieves objects from the  store.
        /// 
        /// 
        public object SetObjectData(object obj, SerializationInfo info, StreamingContext context, ISurrogateSelector selector)
        {
            Person person = (Person)obj;
            person.Name = info.GetString("Name");
            person.Age = info.GetInt32("Age");
            person.License = (DriversLicense) info.GetValue("License", typeof(DriversLicense));
            return person;
        }
    }
    
    public class DriversLicenseSurrogate : ISerializationSurrogate
    {
        /// 
        /// Manually add objects to the  store.
        /// 
        public void GetObjectData(object obj, SerializationInfo info, StreamingContext context)
        {
            DriversLicense license = (DriversLicense)obj;
            info.AddValue("Number", license.Number);
        }
    
        /// 
        /// Retrieves objects from the  store.
        /// 
        /// 
        public object SetObjectData(object obj, SerializationInfo info, StreamingContext context, ISurrogateSelector selector)
        {
            DriversLicense license = (DriversLicense)obj;
            license.Number = info.GetString("Number");
            return license;
        }
    }
    

    Then you need to let your IFormatter know about the surrogates by defining and initializing a SurrogateSelector and assigning it to your IFormatter.

    private static void SerializePerson(Person person)
    {
        if (person == null)
            throw new ArgumentNullException("person");
    
        using (var memoryStream = new MemoryStream())
        {
            //Configure our surrogate selectors.
            var surrogateSelector = new SurrogateSelector();
            surrogateSelector.AddSurrogate(typeof (Person), new StreamingContext(StreamingContextStates.All),
                                           new PersonSurrogate());
            surrogateSelector.AddSurrogate(typeof (DriversLicense), new StreamingContext(StreamingContextStates.All),
                                           new DriversLicenseSurrogate());
    
            //Serialize the object
            IFormatter formatter = new BinaryFormatter();
            formatter.SurrogateSelector = surrogateSelector;
            formatter.Serialize(memoryStream, person);
    
            //Return to the beginning of the stream
            memoryStream.Seek(0, SeekOrigin.Begin);
    
            //Deserialize the object
            Person deserializedPerson = (Person) formatter.Deserialize(memoryStream);
        }
    }
    

    Using a serialization surrogate is by no means straightforward, and can actually become quite verbose when the type you are trying to serialize has private & protected fields that need to be serialized.

    But as you are already manually serializing the values you need, I don't think that is an issue. The use of a surrogate is a more unifom way of handling a scenario like this and should make you feel more comfortable.

提交回复
热议问题