Обновление свойств двоичного класса Serialized c# .NET эффективно повреждает файлы

Я создал класс Car, который я использую для хранения предустановленных сериализованных версий Cars со всеми их различными свойствами и тем, что у вас есть.

По мере выполнения моей программы я понял, что если я добавлю или удалю свойство Car, каждый ранее сериализованный файл станет нечитаемым. Это, как вы понимаете, проблема.

Как я могу обновить свой класс, не аннулируя все предыдущие файлы?

-- Щелчок

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

using System.Runtime.Serialization.Formatters.Binary;
using System.Runtime.Serialization;
using System.IO;
using System;


namespace MyCars
{

    [Serializable]
    public class Car
    {
        public string Name { get; set; }
        public double TopSpeed { get; set; }

        public Car(string name, double topspeed)
        {
            Name = name;
            TopSpeed = topspeed;
        }
    }


    public static class Serializer
    {
        public static bool LoadCar(string filePath, out Car car)
        {
            Stream TestFileStream = File.OpenRead(filePath);
            BinaryFormatter serializer = new BinaryFormatter();

            try
            {
                car = (Car)serializer.Deserialize(TestFileStream);
            }
            catch (Exception ex)
            {
                Console.WriteLine("Could not deserialize");
                TestFileStream.Close();
                car = null;
                return false;
            }

            return true;
        }

        public static bool SaveCar(string filePath, Car car)
        {
            Stream TestFileStream = File.Create(filePath);
            BinaryFormatter serializer = new BinaryFormatter();
            serializer.Serialize(TestFileStream, car);
            TestFileStream.Close();

            return true;
        }
    }

}

Тогда не использовать двоичную сериализацию?

DavidG 09.12.2020 17:57

Как вы его десериализуете?

Shloime Rosenblum 09.12.2020 17:58

Пожалуйста, опубликуйте свой код

Shloime Rosenblum 09.12.2020 17:59

Использовать сериализацию json и игнорировать отсутствующие свойства

Jonathan Alfaro 09.12.2020 18:04

Я должен использовать двоичную сериализацию для этой конкретной цели. Я не могу использовать JSON. Я просто использую встроенный атрибут [Serializable]. Я опубликую пример кода, он не показался мне нужным, так как мне он показался чисто теоретическим, извиняюсь.

ClicketyClackety 09.12.2020 18:19

Единственный способ - включить номер версии в имя файла, чтобы вы могли иметь разные версии классов для прямой/обратной совместимости.

jdweng 09.12.2020 18:47

@ClicketyClackety не использует BinaryFormatter. Он не только очень хрупкий, но и ненадежный и непоправимый. На странице документации есть очень серьезное предупреждение, объясняющее, что BinaryFormatter is insecure and can't be made secure. этот класс планируется удалить уже много лет, и он даже не был добавлен в .NET Core 1.0. Он был добавлен позже только для целей совместимости с ухудшенной производительностью.

Panagiotis Kanavos 09.12.2020 19:09

@ClicketyClackety, чтобы увидеть, насколько серьезно MS относится к этому Методы сериализации BinaryFormatter устарели и запрещены в приложениях ASP.NET. Как и в исключениях во время выполнения, они устарели. Вместо этого используйте буферы протокола

Panagiotis Kanavos 09.12.2020 19:29

Спасибо @PanagiotisKanavos, я никогда не замечал этих предупреждений. Я думаю, я мог бы использовать xml/json и хранить биты данных, которые мне нужны, чтобы быть двоичными внутри них, сохраняя при этом текст в виде строк и т. д.

ClicketyClackety 09.12.2020 19:47

@ClicketyClackety protobuf сохраняет типы, даже сложные. Вам также не нужно беспокоиться о фактической форме, поскольку она поддерживается на нескольких платформах и на большинстве языков. Вы можете сериализовать в C# и десериализовать в Java, JavaScript, Go, C++, Python. Изменения схемы поддерживаются, если вы соблюдаете некоторые правила. Посмотрите введение в C#, например

Panagiotis Kanavos 10.12.2020 09:21
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
10
208
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Двоичная сериализация, реализованная System.Runtime.Serialization.Formatters.Binary, представляет собой двоичный формат без схемы. Это означает, что если сериализатор увидит поле int, он запишет 4 байта в файл, как и все другие поддерживаемые типы. Это очень быстро, но не гибко.

Это отличается от сериализатора, который также записывает схему, которая записывает 4 байта, а также имя поля, поэтому позже десериализатор может смешивать и сопоставлять. Как вы можете себе представить, это медленнее, но гораздо более гибко.

Пока вы придерживаетесь первого, просто не меняйте схему. Там не так много еще вы можете сделать с ним.

Вот почему все собираются (и уже рекомендовали) использовать сериализатор схемы, такой как JSON, BSON (двоичный json), протобуфер Google, XML, базу данных Sql или Nosql, что угодно еще на самом деле, особенно во время разработки, когда схемы классов меняйте часто.

Спасибо за это, я вообще не знал. Это очень полезно знать. Я взглянул на интерфейс ISerializer в MSDN:learn.microsoft.com/en-us/dotnet/api/… Я предполагаю, что даже если двоичный файл не содержит схемы, я могу вставить свои собственные уловы и решить эти вопросы?

ClicketyClackety 09.12.2020 19:47

Вы можете взять на себя автоматический процесс и реализовать свой собственный, это правильно. Одна проблема, с которой вы столкнетесь, заключается в том, что у вас также нет недостающей информации, вы не знаете, десериализуете ли вы версию со свойством car или нет. И будет только хуже, если у вас будет больше изменений в типе.

Blindy 09.12.2020 21:55

Спасибо, Блинди, все это были отличные моменты. И спасибо всем остальным, теперь я, скорее всего, изменю свое решение :)

ClicketyClackety 09.12.2020 23:49

Другие вопросы по теме

Как отобразить выбранную строку в текстовом поле MVP С#
Подсчитайте количество символов в строке и удалите дубликаты
500 ошибок при обслуживании статического контента с сайтов ASP .Net Framework 4.5 с использованием пользовательской учетной записи в пуле приложений
Добавить метаданные для всех вызовов службы gRPC
Является ли Task.Delay действительно асинхронным, как операция ввода-вывода, т. е. полагается ли он на аппаратное обеспечение и прерывания вместо потока?
Совместное использование файлов cookie аутентификации между приложениями .net 4x и .net 5 — доступ к пользовательскому принципу ClaimsPrinciple
Почему невозможно вызвать .ToArray непосредственно в GroupCollection, даже если это IEnumerable?
Удалить ключевые слова «ключ», «значение», когда List<KeyValuePair> сериализуется в Json?
Реализация функции удаления определенной записи в Muddatagrid
Как установить для свойства IsVisible элементов xaml значение true, если связанное логическое свойство имеет значение false?