当你没有类的源代码时,是否可以对对象进行.NET二进制序列化?

我正在使用BinaryFormatter对C#中的某些对象进行二进制序列化。 但是,某些对象包含我通过DLL访问但没有源代码的类,因此我无法使用Serializable属性标记它们。 是否有一种简单的方法来序列化它们? 我有一个解决方法,涉及获取类NoSource并创建一个新类SerializableNoSource ,构造函数接受一个NoSource对象并NoSource提取我需要的所有信息,但它很糟糕。 还有更好的选择吗?

您可以创建序列化代理

想象一下,我们在引用的程序集中定义了一个类,我们无法控制它,如下所示:

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

为了序列化此对象,您需要为对象图中的每个类型定义序列化代理。

要创建序列化代理,您只需创建一个实现ISerializationSurrogate接口的类型:

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

然后,您需要通过定义和初始化SurrogateSelector并将其分配给您的IFormatter来让您的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); } } 

使用序列化代理绝不是直截了当的,当您尝试序列化的类型具有需要序列化的私有和受保护字段时,实际上可能会变得非常冗长。

但是,由于您已经手动序列化了所需的值,我认为这不是问题。 使用代理是一种更加统一的处理这种情况的方式,应该让你感觉更舒服。

您可以使用Mono.Cecil将[SerializableAttribute]添加到类中,但如果有另一种方法可以实现所需的结果,我就不会这样做。

我同意@Servy,如果该类的作者没有预料到它会被序列化,你不应该尝试直接序列化它。 所以从架构的角度来看,你做的是正确的事情。 为了减少当前的方法,“hacky”,考虑为包含对非可序列化对象的引用的类实现ISerializable 。

创建一个新类,inheritance未标记序列化属性的现有类,并实现ISerializable接口。

如果该类是密封的,那么你可以使用Json.NET然后将其转换为二进制,反之亦然(很长时间,如果没有其他任何东西可以帮助使用它:))。

我认为更清洁的方法是实现ISerializable接口并自己管理序列化和反向过程。 在MSDN中,我们可以找到:

序列化在编译后无法添加到类中….