引用this回答问题。
可以改写为:
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)一个新的BinaryFormatter?
这段代码路径非常频繁,因为它涉及我们的缓存层,我希望尽可能轻量化。
感谢。
答案 0 :(得分:10)
根据MSDN:
任何公共静态(在Visual中共享) 基本)这种类型的成员是线程 安全。任何实例成员都不是 保证是线程安全的。
因此,您需要同步对Serialize / Deserialize方法的访问。
您是否每次都通过创建本地序列化程序实例来识别特定的性能问题?
更新:
我相信MSDN,因为即使在某些情况下我们可以验证实例成员可能是线程安全的,但这并不意味着对于下一个Service Pack / update / framework版本,这将继续是这种情况。
在BinaryFormatter构造函数中使用Reflector查找:
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
)应该非常快。恕我直言,大部分时间都花在序列化/反序列化方法上。
答案 1 :(得分:7)
您可以使用[ThreadStatic]属性并初始化value是否为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);
}
}
当然,另一种选择是使用Red Gate的Relfector.Net并查看二进制格式化程序的实现。阅读完代码后,您应该能够确定是否可以安全地进行交叉线程使用;但是,达林是正确的,因为它可能在未来的版本中破裂。