XmlSerializer 不再忽略使用 ObsoleteAttribute 标记的属性

从 .NET 10 开始,XmlSerializer 的行为发生了变化,尤其是在处理由 ObsoleteAttribute 属性标记的属性时。 以前,标记为 [Obsolete] 标记的属性被视为也标有 [XmlIgnore]属性,导致它们被排除在 XML 序列化之外。 此行为是意外的,已被更正。

进行此更改后,标记为[Obsolete]的属性现在默认被序列化,除非属性IsError已设置为trueIsError如果是true,序列化程序会在InvalidOperationException创建过程中引发。 此外,还引入了 AppContext 开关, Switch.System.Xml.IgnoreObsoleteMembers以允许开发人员在必要时还原到以前的行为。

已引入的版本

.NET 10 预览版 1

以前的行为

在早期版本的 .NET 中,标记为 [Obsolete] 属性的属性已从 XML 序列化中排除,类似于使用 [XmlIgnore]标记的属性。 此行为超出了预期,与 [Obsolete] 属性的设计宗旨不符,该属性的用途是提供关于已弃用 API 的编译时警告。

public class Example
{
    public string NormalProperty { get; set; } = "normal";
    
    [Obsolete("This property is deprecated")]
    public string ObsoleteProperty { get; set; } = "obsolete";
    
    [XmlIgnore]
    public string IgnoredProperty { get; set; } = "ignored";
}

var obj = new Example();
var serializer = new XmlSerializer(typeof(Example));
using var writer = new StringWriter();
serializer.Serialize(writer, obj);
Console.WriteLine(writer.ToString());

更改前的输出:

<Example>
  <NormalProperty>normal</NormalProperty>
</Example>

新行为

从 .NET 10 开始,默认情况下,标记为 [Obsolete] 的属性不再从 XML 序列化中排除。 相反:

  • 如果将[Obsolete]属性应用了IsError = false(默认值),则它会被正常序列化。
  • 如果[Obsolete]属性与IsError = true一起应用,XmlSerializer会在序列化程序创建过程中抛出InvalidOperationException

使用与上一行为部分所示相同的代码,更改后的输出为:

<Example>
  <NormalProperty>normal</NormalProperty>
  <ObsoleteProperty>obsolete</ObsoleteProperty>
</Example>

如果 [Obsolete(IsError = true)] 应用于属性,则序列化程序创建期间会引发以下异常:

System.InvalidOperationException:无法序列化成员“ObsoleteProperty”,因为它被标记为 ObsoleteAttribute,IsError 设置为 true。

注释

在 XML 中存在数据时,标记为 [Obsolete] 的属性总能成功完成反序列化。 虽然此更改允许 [Obsolete] 属性在对象与 XML 之间进行“往返”转换,但新行为仅影响“往返”转换中的序列化阶段(对象到 XML)。

破坏性变更的类型

此更改为行为更改

更改原因

之前将 [Obsolete] 视为与 [XmlIgnore] 等同的行为是无意的,并且与 [Obsolete] 属性的目的不一致。 此更改可确保 [Obsolete] 仅用于提供编译时警告,不会影响运行时序列化行为。 AppContext 开关的引入允许开发人员在需要时选择启用旧版本行为。

检查代码库中是否有任何对先前行为的依赖性,即 [Obsolete] 属性被排除在 XML 序列化之外。 如果仍需要此行为,请启用 AppContext 开关 Switch.System.Xml.IgnoreObsoleteMembers ,如下所示:

AppContext.SetSwitch("Switch.System.Xml.IgnoreObsoleteMembers", true);

如果任何属性被标记为 [Obsolete(IsError = true)] 并正在序列化,请更新代码以删除 [Obsolete] 属性,或设置 IsError = false 以避免运行时异常。

受影响的 API