派生类的Xml序列化直到运行时才知道

时间:2014-08-12 09:57:33

标签: c# .net xml xsd

我目前正在实现一个处理符合标准Xml架构的Xml文件的工具。到目前为止,我已经从使用Xml序列化属性的模式生成了类,我使用XmlSerializer进行反序列化,并且使用了标准模式。

但是,架构具有各种扩展点,并且直到运行时才知道这些扩展。这个的简化示例可能如下所示:

// ==== In main assembly ====

public class DeclarationRealisation 
{
    public DataType dataType { get; set; }
}

[XmlInclude(typeof(String)), XmlInclude(typeof(Integer))]  
public abstract class DataType : ExtensionInterface { /* ... */ }

// ==== In extension assembly ====

public class Struct : DataType { /* ... */ }

Struct有自己的xsd文件导入主xsd 如果我将Struct放入主程序集中,即使没有XmlInclude属性(也许sgen执行此操作),一切运行良好。但是如果我将Struct放入它自己的程序集中(我们将处理扩展的方式),我得到一个InvalidOperation声明“指定的类型未被识别”。由于扩展在运行时加载,我无法使用XmlInclude

我已经了解了实现IXmlSerializable的可能性,但我宁愿避免手动执行此操作,因为它有很多类。所以,我的问题是这些:

  • 有没有办法实现这种可扩展性而无需实施IXmlSerializable

  • 如果没有,是否有工具/代码生成器可以处理这样的场景(通过生成界面或任何其他方式)?

注意:我知道你可以在创建XmlSerializers时指定额外的类型,但是自动生成的XmlSerializers的启动命中(在我的情况下> 3秒没有扩展名)对我的用例来说有点多了我想喜欢避免它。

编辑:考虑一下,如果在第一次启动期间发生一次性能损失,则可能是可以接受的。有没有办法在运行时生成序列化程序集?我曾经听说sgen只是一些框架类的命令行客户端,但我再也找不到它了。

2 个答案:

答案 0 :(得分:1)

您可以在XmlSerializer constructor的第二个参数中指定所有类型。

var serializer = new XmlSerializer(typeof(DeclarationRealisation), new Type[] { typeof(Struct) });

DeclarationRealisation result;
using (var reader = new StreamReader("Test.xml"))
{
    result = serializer.Deserialize(reader) as DeclarationRealisation;
}

答案 1 :(得分:0)

好的,事实证明&gt; 3秒的性能影响是因为我使用通用Deserialize<T>方法按需生成匹配的序列化器。即使我缓存它们,每次我传递一个新类型时都会生成一个新的序列化程序,包括代码生成和编译,这些都是累积的。

所以现在我创建一个List<Type>所有类型,我将使用此方法反序列化,并添加所有扩展类型,然后我一次生成所有必需的序列化器:

var deserializedTypes = new List<Type> {
    typeof(DeclarationRealisation) // ...etc...
};

foreach (var extensionType in extensionTypes) { // Includes Struct and more
    deserializedTypes.Add(extensionType);
}

var generatedSerializers = XmlSerializer.FromTypes(deserializedTypes.ToArray());
for (int i = 0; i < generatedSerializers.Length; i++) {
    var xmlType = deserializedTypes[i];
    var serializer = generatedSerializers[i];
    serializers[xmlType] = serializer;
}

使用这种方法,启动命中减少到约0.45秒,这在某种程度上是可以接受的。

如果我现在可以以某种方式保存生成的程序集以在后续启动时使用它,那真的很棒,但似乎生成的类型InternalAssemblyBuilder的程序集无法保存它(我会感激任何暗示这一点)。但就目前而言,这还不错。