Безопасны ли потоки BinaryFormatter для сериализации и десериализации? - PullRequest
14 голосов
/ 21 сентября 2009

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

Может ли это быть переписано как:

    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 ]

10 голосов
/ 21 сентября 2009

Согласно MSDN :

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

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

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


UPDATE:

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

Взгляд с помощью Reflector на конструктор 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) должно быть ослепительно быстрым. ИМХО большую часть времени будет уделено методам сериализации / десериализации.

7 голосов
/ 21 сентября 2009

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

[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 и проверить реализацию двоичного форматера. После прочтения кода вы сможете решить, является ли он безопасным для перекрестного использования; тем не менее, Дарин прав в том, что он может сломаться в будущем выпуске.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...