Безопасны ли сериализация и десериализация потоков BinaryFormatter?

ссылка этой ответ на вопрос.

Это можно переписать как:

    private static BinaryFormatter formatter = new BinaryFormatter();

    public static T DeepClone<T>(this T a)
    {
        using(MemoryStream stream = new MemoryStream())
        {
            formatter.Serialize(stream, a);
            stream.Position = 0;
            return (T)formatter.Deserialize(stream);
        }
    }

таким образом, избегая построения (и GC'ING) нового BinaryFormatter для каждого вызова?

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

спасибо.

2 ответов


По данным MSDN:

любые открытые статические (shared в Visual Basic) члены этого типа являются нити безопасный. Члены экземпляров не гарантированно будет потокобезопасным.

поэтому вам нужно синхронизировать доступ к методам сериализации / десериализации.

вы определили конкретные проблемы производительности, создавая локальный экземпляр сериализатора каждый раз?


обновление:

Я бы доверил MSDN, потому что даже если в некоторых случаях мы можем проверить, что члены экземпляра могут быть потокобезопасными, это не означает, что со следующей версией пакета обновления/обновления/framework это будет продолжаться.

глядя с отражателем на конструктор BinaryFormatter:

public BinaryFormatter()
{
    this.m_typeFormat = FormatterTypeStyle.TypesAlways;
    this.m_securityLevel = TypeFilterLevel.Full;
    this.m_surrogates = null;
    this.m_context = new StreamingContext(StreamingContextStates.All);
}

и конструктор StreamingContext:

public StreamingContext(StreamingContextStates state, object additional)
{
    this.m_state = state;
    this.m_additionalContext = additional;
}

откровенно говоря, присвоение 6 свойств (большинство из которых enums) следует молниеносно. ИМХО большую часть времени будет проводить в Сериализация / десериализация методов.


вы можете использовать атрибут [ThreadStatic] и инициализировать, если значение равно null. Это будет работать, предполагая, что вы повторно используете потоки.

[ThreadStatic]
private static BinaryFormatter formatter = null;

public static T DeepClone<T>(this T a)
    {
            if( formatter == null ) formatter = new BinaryFormatter();
            using(MemoryStream stream = new MemoryStream())
            {
                    formatter.Serialize(stream, a);
                    stream.Position = 0;
                    return (T)formatter.Deserialize(stream);
            }
    }

конечно, другой вариант-использовать Relfector.Net от Red Gate и обзор реализации двоичного форматирования. После прочтения кода Вы сможете решить, безопасен ли он для использования с перекрестной резьбой; однако Дарин прав в том, что он может сломаться в будущем выпуске.