You need to enable JavaScript to run this app. C#使用XmlMessageFormatter反序列化含嵌套内部类的XML失败求助
优惠活动
大模型
产品
解决方案
定价
更多

C#使用XmlMessageFormatter反序列化含嵌套内部类的XML失败求助

问题描述

编辑

我在反序列化包含内部类(嵌套类)的XML文件时遇到问题。

我的类定义如下:

[XmlRoot(ElementName = "HM")]
public class OwnClass : BaseClass{

...
public OwnClass(){} // 默认构造函数
...
}

我基于System.Messaging声明了如下_xmlMessageFormatter:

this._xmlMessageFormatter = new System.Messaging.XmlMessageFormatter();
System.Type[] OwnTypes = new System.Type[30];
OwnTypes[0] = typeof(Baseclasses.OwnClass);                   /* TR */
...
this._xmlMessageFormatter.TargetTypes = OwnTypes;

编辑:原XML格式如下:

<?xml version="1.0"?>
<HM xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    <ID>124</ID>
    <TC>TR</TC>
</HM>

上述代码运行完全正常。

现在我在OwnClass的定义内新增了一个内部类:

[XmlRoot(ElementName = "HM")]
public class OwnClass : BaseClass {
    [XmlElement(ElementName = "INS")]
    public ClassInside f_Inside;

    ...
    public OwnClass(){} // 默认构造函数
    ...
    public class ClassInside{
    ...
    public ClassInside(){}
        ...} // ClassInside定义结束
    } // OwnClass定义结束

(注:原代码中构造函数多写的class关键字为笔误)

我也已经添加了对应的目标类型:

OwnTypes [27] = typeof(BaseClasses.OwnClass.ClassInside); // 数组下标正确。

编辑:修改后的XML格式如下:

<?xml version="1.0"?>
<HM xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    <ID>125</ID>
    <TC>TR</TC>
    <TR>
        <ID>1</ID>
        <CD>MOVE</CD>
    </TR>
</HM>

此时_xmlMessageFormatter无法完成反序列化,相关代码如下:
源代码:

Object temp;
temp = this._xmlMessageFormatter.Read(message);

为获取更多信息,我在Visual Studio的即时窗口输入? temp = this._xmlMessageFormatter.Read(message);,得到如下报错:

'temp = this._xmlMessageFormatter.Read(message)' threw an exception of type 'System.InvalidOperationException'
    Data: {System.Collections.ListDictionaryInternal}
    HResult: -2146233079
    HelpLink: null
    InnerException: {"There was an error reflecting field 'f_Inside'."}
    Message: "There was an error reflecting type 'BaseClasses.AnotherClass'."
    Source: "System.Xml"
    StackTrace: "   at System.Xml.Serialization.XmlReflectionImporter.ImportTypeMapping(TypeModel model, String ns, ImportContext context, String dataType, XmlAttributes a, Boolean repeats, Boolean openModel, RecursionLimiter limiter)\r\n   at 
System.Xml.Serialization.XmlReflectionImporter.ImportElement(TypeModel model, XmlRootAttribute root, String defaultNamespace, RecursionLimiter limiter)\r\n   at 
System.Xml.Serialization.XmlReflectionImporter.ImportTypeMapping(Type type, XmlRootAttribute root, String defaultNamespace)\r\n   at 
System.Xml.Serialization.XmlSerializer..ctor(Type type, String defaultNamespace)\r\n   at 
System.Messaging.XmlMessageFormatter.CreateTargetSerializerTable()\r\n   at 
System.Messaging.XmlMessageFormatter.Read(Message message)"
    TargetSite: {System.Xml.Serialization.TypeMapping ImportTypeMapping(System.Xml.Serialization.TypeModel, 
System.String, 
ImportContext, 
System.String, 
System.Xml.Serialization.XmlAttributes, 
Boolean, 
Boolean, 
System.Xml.Serialization.RecursionLimiter)}

我对报错信息存在两个疑问:

  • 报错提到f_Inside,看起来是对的,但我所有类都通用f_Inside作为字段名,这也引出第二个问题:
  • 我发送的是OwnClass类型的消息,但报错却提到了AnotherClass。

我非常怀疑报错信息的准确性,请问有没有人知道我现在该怎么排查,或者_xmlFormatter的运行原理是什么?

编辑:补充背景信息

上述代码属于一个消息服务:一个应用发消息,另一个应用通过System.Messaging.MessageQueue对象接收,序列化/反序列化是其中的一个环节。


解决方案

运行原理说明

XmlMessageFormatter在第一次调用Read方法时,会为TargetTypes数组中所有注册的类型预生成对应的XmlSerializer实例,生成过程中会递归扫描每个类型的所有公开字段、属性,校验序列化规则是否合法,只要任意一个类型校验失败就会直接抛出异常,和当前要反序列化的消息实际所属类型无关。这就是你发送OwnClass类型消息,却报AnotherClass错误的核心原因:全局扫描时先触发了AnotherClass的序列化规则校验失败。

排查和修复步骤

  1. 先修正OwnClass的明显配置错误:你给f_Inside字段标注的[XmlElement(ElementName = "INS")]和XML中实际的<TR>节点名不匹配,把特性值改成ElementName = "TR",保证两边节点名一致。
  2. 修正代码语法错误:你贴的ClassInside构造函数多写了class关键字,正确写法是public ClassInside(){},这个语法错误会直接导致反射失败。
  3. 排查所有带f_Inside字段的类型,重点是报错提到的AnotherClass:
    • 确认它的内部类有public无参构造函数
    • 确认内部类的所有公开字段/属性都是可序列化的类型,没有标注[XmlIgnore]外的不可序列化特性
    • 确认它的f_Inside字段的Xml特性配置和对应XML结构匹配
  4. 缩小调试范围:临时把AnotherClass从OwnTypes数组中移除,验证OwnClass的反序列化逻辑是否能正常运行,再逐步把其他类型加回去,快速定位问题类型。
  5. 单个类型快速验证:可以单独生成XmlSerializer测试对应类型的反序列化逻辑,绕过XmlMessageFormatter的全局扫描,快速定位单个类型的问题:
// 测试OwnClass反序列化
string xmlContent = "这里填你要测试的XML字符串";
var serializer = new XmlSerializer(typeof(Baseclasses.OwnClass));
using (var reader = new StringReader(xmlContent))
{
    var result = serializer.Deserialize(reader);
}

内容的提问来源于stack exchange,提问作者Dominique

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.14 10:24:05