Можно ли выполнять бинарную сериализацию .NET в случае, если у вас нет исходного кода classа?

Я использую BinaryFormatter для выполнения двоичной сериализации некоторых объектов в C #. Однако некоторые объекты содержат classы, к которым я обращаюсь через DLL, и у меня нет исходного кода, поэтому я не могу пометить их атрибутом Serializable . Есть ли простой способ их сериализации? У меня есть обходное решение, которое предполагает использование classа NoSource и создание нового classа SerializableNoSource для которого конструктор берет объект NoSource и извлекает всю необходимую мне информацию, но он взломан. Есть ли лучшие альтернативы?

    Вы можете создать суррогат сериализации .

    Представьте, что у нас есть class, определенный в ссылочной сборке, который у нас нет контроля над тем, что выглядит следующим образом:

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

    Затем вы должны сообщить своему IFormatter о суррогатах, IFormatter и инициализируя SurrogateSelector и назначив его вашему 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] к classам, но я не сделал бы этого, если есть другой способ достижения желаемого результата.

    Я согласен с @Servy, если автор classа не ожидал, что он будет сериализован, вам не следует пытаться сериализовать его напрямую. Таким образом, вы делаете правильные вещи с архитектурной точки зрения. Чтобы сделать ваш текущий подход меньше, «взломанный», рассмотрите возможность внедрения ISerializable для classов, содержащих ссылки на объекты, не связанные с сериализацией.

    Создайте новый class, наследуйте существующий class, который не помечен атрибутом сериализации, и реализуйте интерфейс ISerializable.

    Если class запечатан, вы можете использовать Json.NET, а затем преобразовать его в двоичный и наоборот (Sucks большое время, используйте его, если ничего не может помочь :)).

    Я думаю, что более чистый способ заключается в том, чтобы внедрить интерфейс ISerializable и управлять сериализацией и обратным процессом. В MSDN мы можем найти:

    Сериализация не может быть добавлена ​​в class после ее компиляции ….

    Давайте будем гением компьютера.