8

我们的项目中有一些设置类,它们使用来自一些 .config-Files 的 XmlSerializer 进行序列化/反序列化。在其中一些设置类中,我们有如下子设置的集合:

using System;
using System.Collections.ObjectModel;
using System.Xml.Serialization;

namespace Datev.Framework.Shared.Actions.Setup
{
    [Serializable]
    [XmlSerializerAssembly]
    [XmlRoot("setup")]
    public class SetupXml
    {
        public SetupXml()
        {
            SubSetups = new Collection<SubSetupXml>();
        }

        [XmlArray("subSetups")]
        [XmlArrayItem("subSetup")]
        public Collection<SubSetupXml> SubSetups { get; private set; }
    }

    [Serializable]
    public class SubSetupXml
    {
        [XmlElement("someValue")]
        public string SomeValue { get; set; }
    }
}

我们使用属性 [XmlSerializerAssembly] 来获得读取和写入设置的最佳性能。这是我的问题:我们正在使用 Collection 来避免 CA 警告“不要使用数组”。当我们公开 SubSetups 的设置器时,我们会收到 CA-Warning CA2227“不要公开集合的设置器”。如果我们将属性 SubSetups 的设置器设为私有(就像在代码示例中一样),我们将在生成的序列化程序中得到一个错误。方法“GenerateSerializer”(在我们的工具中调用)代码有这样一行:

if (o.SubSetups == null) o.SubSetups = new Collection<SubSetupXml>();

如果我们将设置器设为私有,我们将在构建序列化器期间获得 CS0200“无法分配属性子设置”。有谁知道如何在不抑制 CA 警告的情况下使用生成的序列化程序进行正确设置?

4

6 回答 6

5

很难说:“正确”的设置很大程度上取决于上下文。一个快速的想法:如果将逻辑从“GenerateSerializer”移动到属性获取器会发生什么?可以接受吗?

[XmlArray("subSetups")]
[XmlArrayItem("subSetup")]
public Collection<SubSetupXml> SubSetups { 
   get {
      // subSetups needs to be a backing (private) field... is this a problem?
      if (this.subSetups == null) this.subSetups = new Collection<SubSetupXml>();
   }
   private set; 
}

这样,在“GenerateSerializer”中你就得到了集合。如果该集合尚未创建,它将位于 getter 内部,而无需在类外部创建它。只是一个想法,让我知道它是否不适用。

于 2013-01-30T11:11:43.960 回答
3

如果情况像看起来那么简单,那么您不需要检查是否(o.SubSetups == null)因为您SubSetups = new Collection<SubSetupXml>();SetupXml()构造函数中有该行(当然,如果o是类型SetupXml)。如果您if从方法中删除该语句GenerateSerializer并将设置器设为私有您应该没问题 -除非有其他一些您没有提到的弄乱它的方法,否则该SubSetups属性是不可能的......null

于 2013-01-30T15:32:10.110 回答
3

你可以有这样的东西:

    public class SetupXml
    {
        public SetupXml()
        {
            SubSetups = new Collection<SubSetupXml>();
        }

        [XmlIgnore]
        public Collection<SubSetupXml> SubSetups { get; private set; }

        [EditorBrowsable(EditorBrowsableState.Never)]
        [GeneratedCodeAttribute("Whatever", "1.0.0.0")]
        [XmlArray("subSetups")]
        [XmlArrayItem("subSetup")]          
        public SubSetupXml[] SerializationSubSetups
        {
            get
            {
                return SubSetups.ToArray();
            }
            get
            {
                SubSetups = new SubSetups();
                if (value != null)
                {
                    foreach(SubSetupXml ssx in value)
                    {
                        SubSetups.Add(ssx);
                    }
                }
            }
        }
    }

它并不完美,但EditorBrowsable属性将阻止开发人员使用此库(来自另一个程序集)看到它由智能感知/自动完成工具显示。GeneratedCode 属性将阻止对其发出 CA 警告。

于 2013-01-31T15:00:00.543 回答
3

我假设您已经查阅过这篇文章? http://msdn.microsoft.com/en-us/library/ms182327.aspx

这让我觉得那篇文章中有一个重要说明:“二进制和 XML 序列化都支持作为集合的只读属性。System.Xml.Serialization.XmlSerializer 类对实现 ICollection 和 System.Collections.IEnumerable 的类型有特定要求为了可序列化。”

除此之外,您可以使用 .Clear() 和 .AddRange() 方法取得更多进展,详见那里。

于 2013-02-01T17:32:44.847 回答
3

您可以尝试实现 IXmlSerializable 接口。它需要更多的工作,但它可以让您很好地控制序列化,并在您的情况下访问私有类变量。在 ReadXml 方法中,您只需创建集合的实例,遍历源 xml 中的每个节点并解析值

于 2013-02-02T20:20:51.660 回答
3

将 SubSetups 的类型更改为IEnumerable将消除代码分析警告,但我不知道这是否适合您。

    [XmlArray("subSetups")]
    [XmlArrayItem("subSetup")]
    public IEnumerable<SubSetupXml> SubSetups { get; set; }
于 2013-01-30T18:29:11.267 回答