Прекомпиляция XmlSerializer с помощью XmlAttributeOverrides
При создании экземпляров XmlSerializer в.NET сборки для сериализации и десериализации указанного типа генерируются динамически. Это трудоемкий процесс. Средство sgen.exe от Microsoft можно использовать для предварительной компиляции экземпляров XmlSerializer для последующего их использования без их динамической генерации. К сожалению, это невозможно с экземплярами XmlSerializer, которые используют XmlAttributeOverrides.
Есть ли способ предварительно скомпилировать эти экземпляры XmlSerializer, чтобы избежать генерации во время выполнения?
1 ответ
Андреас, это не проблема самого инструмента sgen, это связано с реализацией XmlSerializer.
Когда вы создаете экземпляр XmlSerializer, используя конструктор только с одним аргументом Type, он проверяет кэш и ищет предварительно сгенерированные сборки. Но когда вы используете конструктор с XmlAttributeOverrides, XmlSerializer не проверяет кэши и сразу генерирует временную сборку.
Скорее всего, это связано с довольно радикальными изменениями в логике сериализации, которые вы можете осуществить с помощью аргумента XmlAttributeOverrides, который нельзя "предвидеть" во время компиляции с помощью таких инструментов, как sgen.
Если вам нужно что-то предварительно скомпилировать, вам [вздох] следует избегать XmlAttributeOverrides. Если это невозможно, попробуйте заранее создать необходимые экземпляры XmlSerializer, возможно, в фоновом потоке.
Просто для вашего интереса, вот код для конструктора по умолчанию (проверяет кеш и пытается найти предварительно сгенерированную сборку):
public XmlSerializer(Type type, string defaultNamespace)
{
this.events = new XmlDeserializationEvents();
if (type == null)
{
throw new ArgumentNullException("type");
}
this.mapping = GetKnownMapping(type, defaultNamespace);
if (this.mapping != null)
{
this.primitiveType = type;
}
else
{
this.tempAssembly = cache[defaultNamespace, type];
if (this.tempAssembly == null)
{
lock (cache)
{
this.tempAssembly = cache[defaultNamespace, type];
if (this.tempAssembly == null)
{
XmlSerializerImplementation implementation;
Assembly assembly = TempAssembly.LoadGeneratedAssembly(type, defaultNamespace, out implementation);
if (assembly == null)
{
this.mapping = new XmlReflectionImporter(defaultNamespace).ImportTypeMapping(type, null, defaultNamespace);
this.tempAssembly = GenerateTempAssembly(this.mapping, type, defaultNamespace);
}
else
{
this.mapping = XmlReflectionImporter.GetTopLevelMapping(type, defaultNamespace);
this.tempAssembly = new TempAssembly(new XmlMapping[] { this.mapping }, assembly, implementation);
}
}
cache.Add(defaultNamespace, type, this.tempAssembly);
}
}
if (this.mapping == null)
{
this.mapping = XmlReflectionImporter.GetTopLevelMapping(type, defaultNamespace);
}
}
}
А вот конструктор, используемый с XmlAttributeOverrides (всегда генерирует сборку сериализации):
public XmlSerializer(Type type, XmlAttributeOverrides overrides, Type[] extraTypes, XmlRootAttribute root, string defaultNamespace, string location, Evidence evidence)
{
this.events = new XmlDeserializationEvents();
if (type == null)
{
throw new ArgumentNullException("type");
}
XmlReflectionImporter importer = new XmlReflectionImporter(overrides, defaultNamespace);
for (int i = 0; i < extraTypes.Length; i++)
{
importer.IncludeType(extraTypes[i]);
}
this.mapping = importer.ImportTypeMapping(type, root, defaultNamespace);
if (location != null)
{
this.DemandForUserLocation();
}
this.tempAssembly = GenerateTempAssembly(this.mapping, type, defaultNamespace, location, evidence);
}