我们可以在使用 XmlSerializer 时将 Flag 枚举值标记为过时吗?

Posted

技术标签:

【中文标题】我们可以在使用 XmlSerializer 时将 Flag 枚举值标记为过时吗?【英文标题】:Can we mark a Flag enumeration value as obsolete when using XmlSerializer? 【发布时间】:2021-02-21 15:19:02 【问题描述】:

我已经看到这个 [问题][1] 它指的是[Obsolete("...")],它听起来像是我可能需要使用的东西。但现在我认为我不能。

我有这个更新的标志枚举:

[Flags]
[Guid("xxxxx")]
[ComVisible(true)]
public enum AssignmentType

    None = 0,
    Attendant = 1,
    ConductorCBS = 2,
    ReaderCBS = 4,
    Chairman = 8,
    Mike = 16,
    PlatformAttendant = 32,
    Prayer = 64,
    OCLM = 128,
    Sound = 256,
    Student = 512,
    Custom = 1024,
    Demonstration = 2048,
    Assistant = 4096,
    Host = 8192,
    CoHost = 16384,
    OCLMTreasures = 32768,
    OCLMGems = 65536,
    OCLMLiving = 131072

为了给你一些上下文,这些标志枚举出现在我的 XML 文件中,如下所示:

      <Assignments Attendant="false" ConductorCBS="false" ReaderCBS="false" Chairman="false" Microphones="false" PlatformAttendant="false" Prayer="false" OCLM="false" Sound="false" Student="false" Assistant="false" Host="false" CoHost="false" OCLMTreasures="false" OCLMGems="true" OCLMLiving="false" Demonstrations="false">

相当简单的东西。现在,我为我的班级添加了一个升级方法:

    public bool UpgradePublisherDatabase()
    
        bool bSaveDB = false;

        try
        
            // Database should already be open

            if(PublisherData.Version < 1)
            
                // CODE SNIPPED

                bSaveDB = true;
            
            
            if(PublisherData.Version < 2)
            
                // We need to upgrade the database
                PublisherData.Version = 2;

                var vPublisherKeys = new List<string>(PublisherData.PublisherDictionary.Keys);
                foreach (string strPublisherKey in vPublisherKeys)
                
                    Publisher oPublisher = PublisherData.PublisherDictionary[strPublisherKey];
                    if (oPublisher.CanUseFor(AssignmentType.OCLM))
                    
                        // We must set the other OCLM flags
                        oPublisher.SetCanUseFor(true, AssignmentType.OCLMTreasures);
                        oPublisher.SetCanUseFor(true, AssignmentType.OCLMGems);
                        oPublisher.SetCanUseFor(true, AssignmentType.OCLMLiving);
                    

                    PublisherData.PublisherDictionary[strPublisherKey] = oPublisher;
                

                bSaveDB = true;
            

            if(bSaveDB)
            
                return SavePublisherData();
            
        
        catch (Exception ex)
        
            SimpleLog.Log(ex);
            return false;
        

        return true;
    

在我的主应用程序 (Visual C++ MFC) 中,它调用我的 DLL 来加载 XML 文件。然后它对文件运行升级方法以使其保持最新状态。

此时,当 XML 文件为版本 2 时,我不再需要 XML 文件中的 AssignmentType.OCLM 标志,因为我不再使用它。但是在序列化时似乎不可能仅将标志枚举值标记为过时?


更新

这是该属性的定义:

   [XmlAttribute("OCLM")]
    public bool UseForOCLMAssignments
    
        get => _Assignments.HasFlag(AssignmentType.OCLM); set
        
            if (value)
                _Assignments |= AssignmentType.OCLM;
            else
                _Assignments &= ~AssignmentType.OCLM;
        
    

所以,我希望能够将其读入,但我不想将其写出。那么在这里使用[Obsolete...] 语法是否可以接受? [1]:Obsolete attribute causes property to be ignored by XmlSerialization

【问题讨论】:

serialize 方法只获取类中的内容并转换为 Xml。因此,如果有人在类中放置了一个过时的值,您希望序列化程序做什么?它确实应该在将数据添加到类的代码中修复。如果值已经存在于类中,我认为你想输出到 xml。 @jdweng 我的软件管理这个 XML 文件。在这个版本之前,我一直在使用那个标志。现在,继续前进,我正在使用三个新标志。但是我必须将枚举保留为有效条目,否则解析器不会崩溃吗?理想情况下,我只想删除该标志,然后当我读入 XML 时,如果它发现这个“未知”OCLM 属性,它会将其他三个属性设置为真。但我不知道XmlSerializer 是否可行。 您可以在类中创建自定义get/set,然后在get/set中添加代码。请参阅以下内容:docs.microsoft.com/en-us/dotnet/csharp/language-reference/… @jdweng 我真的不明白。我已经按照我向你展示的那样定义了我的对象。 【参考方案1】:

最后,这就是我所需要的:


    [Obsolete("Use the OCLMTreasures, OCLMGems and OCLMLiving flag values instead.")]
    [XmlAttribute("OCLM")]
    public bool UseForOCLMAssignments
    
        get => _Assignments.HasFlag(AssignmentType.OCLM); set
        
            if (value)
                _Assignments |= AssignmentType.OCLM;
            else
                _Assignments &= ~AssignmentType.OCLM;
        
    

所以Obsolete 关键字毕竟是要走的路。

【讨论】:

以上是关于我们可以在使用 XmlSerializer 时将 Flag 枚举值标记为过时吗?的主要内容,如果未能解决你的问题,请参考以下文章

无法使用 c# xmlserializer 反序列化以前序列化的 XML

如何使用 .NET XmlSerializer 使值类型可以为空?

在C#中 如何序列化图片 用System.Xml.Serialization.XmlSerializer这个可以吗?如果可以的话怎样使用?

XmlSerializer(Type type, Type[] extraTypes) 内存泄漏

使用 XmlSerializer 将 XML 反序列化为类型

我可以让 XmlSerializer 在反序列化时忽略命名空间吗?