Поделиться через


BinaryFormatter Справочник по функциям

Впервые BinaryFormatter был представлен первоначальный выпуск платформа .NET Framework в 2002 году. Чтобы понять, как заменить использование BinaryFormatter, он помогает узнать, как BinaryFormatter работает.

BinaryFormatter может сериализовать любой экземпляр любого типа, помеченного или [Serializable] реализующего ISerializable интерфейс.

Имена членов

В большинстве случаев тип аннотируется и [Serializable] сериализатор использует отражение для сериализации всех полей (как общедоступных, так и не открытых), за исключением тех, с которыми задается аннотация [NonSerialized]. По умолчанию сериализованные имена элементов будут соответствовать именам полей типа. Это исторически привело к несовместимости, если даже частные поля переименованы в [Serializable] типы. Во время миграции от BinaryFormatterнего необходимо понять, как сериализованные имена полей обрабатываются и переопределяются.

Автоматические свойства C#

Для C# автоматически реализованные свойства ({ get; set; }) BinaryFormatter сериализуют резервные поля, созданные компилятором C#, а не свойства. Имена этих сериализованных полей резервной копии содержат недопустимые символы C# и не могут контролироваться. Декомпилатор C# (например https://sharplab.io/ , ILSpy) может продемонстрировать, как автоматические свойства C# отображаются в среде выполнения.

[Serializable]
internal class PropertySample
{
    public string Name { get; set; }
}

Предыдущий класс преобразуется компилятором C# в:

[Serializable]
internal class PropertySample
{
    private string <Name>k__BackingField;

    public string Name
    {
        get
        {
            return <Name>k__BackingField;
        }
        set
        {
            <Name>k__BackingField = value;
        }
    }
}

В этом случае <Name>k__BackingFieldэто имя элемента, который BinaryFormatter используется в сериализованной полезных данных. Невозможно использовать nameof или любой другой оператор C#, чтобы получить это имя.

Интерфейс ISerializable поставляется с GetObjectData методом, который позволяет пользователям управлять именами с помощью одного из AddValue методов.

// Note lack of any special attribute.
public void GetObjectData(SerializationInfo info, StreamingContext context)
{
    info.AddValue("Name", this.Name);
}

Если такая настройка была применена, необходимо также предоставить информацию во время десериализации. Это возможно с помощью конструктораserialization, где все значения считываются с SerializationInfo помощью одного из Get методов, которые он предоставляет.

private PropertySample(SerializationInfo info, StreamingContext context)
{
    this.Name = info.GetString("Name");
}

Примечание.

Оператор nameof не использовался здесь, так как полезные данные могут быть сохранены, и свойство может быть переименовано позже. Таким образом, даже если он получает переименование (скажем, FirstName потому что вы решили также ввести LastName свойство), чтобы оставаться обратно совместимым, serialization следует по-прежнему использовать старое имя, которое может быть сохранено где-то.

Serialization сноповязалка

Рекомендуется использовать SerializationBinder для управления загрузкой классов и мандатом на загрузку класса. Это сводит к минимуму уязвимости безопасности (поэтому только разрешенные типы загружаются, даже если злоумышленник изменяет полезные данные для десериализации и загрузки чего-либо другого).

Для использования этого типа требуется наследование от него и переопределение BindToType метода.

В идеале список сериализуемых типов закрыт, так как это означает, что вы знаете, какие типы можно создать, что поможет снизить уязвимости системы безопасности.