我目前有一个非常奇怪的问题,我似乎无法弄清楚如何解决它。
我有一个相当复杂的类型,我正在尝试使用XmlSerializer类进行序列化。这实际上运行正常,类型序列化正确,但似乎非常长时间这样做;大约5秒钟,具体取决于对象中的数据。
经过一些分析后,我把问题缩小了 - 奇怪 - 在调用XmlSerializer.Serialize时指定了一个XmlRootAttribute。我这样做是为了将从ArrayOf序列化的集合的名称更改为更有意义的东西。删除参数后,操作几乎是即时的!
任何想法或建议都会很棒,因为我完全不知道这个!
答案 0 :(得分:24)
只为遇到此问题的其他人;使用上面的答案和MSDN中的示例,我设法使用以下类解决此问题:
public static class XmlSerializerCache
{
private static readonly Dictionary<string, XmlSerializer> cache =
new Dictionary<string, XmlSerializer>();
public static XmlSerializer Create(Type type, XmlRootAttribute root)
{
var key = String.Format(
CultureInfo.InvariantCulture,
"{0}:{1}",
type,
root.ElementName);
if (!cache.ContainsKey(key))
{
cache.Add(key, new XmlSerializer(type, root));
}
return cache[key];
}
}
然后我不使用默认的XmlSerializer构造函数来获取XmlRootAttribute,而是使用以下代码:
var xmlRootAttribute = new XmlRootAttribute("ExampleElement");
var serializer = XmlSerializerCache.Create(target.GetType(), xmlRootAttribute);
我的应用程序现在再次执行!
答案 1 :(得分:18)
正如对原始问题的后续评论中所提到的,.NET在创建XmlSerializers时会发出程序集,如果使用这两个构造函数之一创建生成的程序集,则会缓存生成的程序集:
XmlSerializer(Type)
XmlSerializer(Type, String)
使用其他构造函数生成的程序集不会被缓存,因此.NET每次都必须生成新的程序集。
为什么呢?这个答案可能不是很令人满意,但是在Reflector中对此嗤之以鼻,您可以看到用于存储和访问生成的XmlSerializer
程序集(TempAssemblyCacheKey
)的密钥只是一个简单的复合密钥。可序列化类型和(可选)其命名空间。
因此,没有机制来判断XmlSerializer
的缓存SomeType
是否具有特殊XmlRootAttribute
或默认值。{/ p>
很难想到密钥无法容纳更多元素的技术原因,所以这可能只是一个没有人有时间实现的功能(特别是因为它会涉及改变其他稳定的类)。
您可能已经看过这个,但是如果您没有看到,the XmlSerializer
class documentation讨论了一种解决方法:
如果你使用其他任何一个 构造函数,多个版本的 生成相同的程序集,永远不会 卸载,这会产生一个记忆 泄漏和性能不佳。最简单的 解决方案是使用其中之一 前面提到了两个构造函数。 否则,你必须缓存
Hashtable,
中的程序集,如图所示 以下示例。
(我在这里省略了这个例子)
答案 2 :(得分:1)
只需实现类似的功能,并使用@ Dougc解决方案的稍微优化版本,方便过载:
public static class XmlSerializerCache {
private static readonly Dictionary<string, XmlSerializer> cache = new Dictionary<string, XmlSerializer>();
public static XmlSerializer Get(Type type, XmlRootAttribute root) {
var key = String.Format("{0}:{1}", type, root.ElementName);
XmlSerializer ser;
if (!cache.TryGetValue(key, out ser)) {
ser = new XmlSerializer(type, root);
cache.Add(key, ser);
}
return ser;
}
public static XmlSerializer Get(Type type, string root) {
return Get(type, new XmlRootAttribute(root));
}
}
答案 3 :(得分:0)
有一个更复杂的实施解释here。但是该项目不再有效。
相关课程在这里可见: http://mvpxml.codeplex.com/SourceControl/changeset/view/64156#258382
特别是,生成唯一键的以下函数可能很有用:
public static string MakeKey(Type type
, XmlAttributeOverrides overrides
, Type[] types
, XmlRootAttribute root
, String defaultNamespace) {
StringBuilder keyBuilder = new StringBuilder();
keyBuilder.Append(type.FullName);
keyBuilder.Append("??");
keyBuilder.Append(SignatureExtractor.GetOverridesSignature(overrides));
keyBuilder.Append("??");
keyBuilder.Append(SignatureExtractor.GetTypeArraySignature(types));
keyBuilder.Append("??");
keyBuilder.Append(SignatureExtractor.GetXmlRootSignature(root));
keyBuilder.Append("??");
keyBuilder.Append(SignatureExtractor.GetDefaultNamespaceSignature(defaultNamespace));
return keyBuilder.ToString();
}