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