【问题标题】:How to Serialize List<T> property in c# without showing its type in XML serialization如何在 C# 中序列化 List<T> 属性而不在 XML 序列化中显示其类型
【发布时间】:2019-01-08 07:39:00
【问题描述】:

我有一个需要用 XML 序列化它的类。下面是例子:

public class StringArray
{        
    public List<string> Days { get; set; }

    public StringArray()
    {
        List<string> s = new List<string>();
        s.Add("Monday");
        s.Add("Tuesday");
        s.Add("Wed");           
        Days = s;
    }
}

当我以 XML 格式对其进行序列化时,结果是:

 <StringArray xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
 xmlns:xsd="http://www.w3.org/2001/XMLSchema">
   <Days>
     <string>Monday</string>
     <string>Tuesday</string>
     <string>Wed</string>
   </Days>
 </StringArray>

但是,我需要如下结果:

 <StringArray xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
 xmlns:xsd="http://www.w3.org/2001/XMLSchema">
   <Days>             
         <Monday />
         <Tuesday />
         <Wed />                 
  </Days>
</StringArray>

其实我不想显示列表项的类型。

请注意,可能的字符串集是固定的。我也尝试为此使用enum,但是XML 显示enum 类型名称而不是“字符串”,这不能解决问题。

【问题讨论】:

  • 您需要使用自定义代码处理 XML 序列化。
  • 你看过docs.microsoft.com/en-us/dotnet/standard/serialization/…吗?具体来说,[XmlArrayItem("MemberName")].
  • 字符串集是固定的还是可变的?例如,在示例情况下,似乎应该只有 7 天。
  • 是的,它是固定的字符串集。我为此使用了 Enum,但是它显示的是枚举类型而不是“字符串”。

标签: c# xml list serialization


【解决方案1】:

由于您只有一组固定的可能字符串值,因此您的架构对应于choice 元素的无限sequence,其中可能的元素名称对应于可能的字符串值。

这可以通过用一些适当的enum 替换string 来建模,然后利用XmlSerializer 内置的Choice Element Binding Support 支持,这需要应用XmlChoiceIdentifierAttribute 以及使用适当的序列化代理DTO

首先,定义一个与可能的字符串值对应的enum

public enum Day
{
    Monday,
    Tuesday,
    Wednesday,
    Thursday,
    Friday,
    Saturday,
    Sunday
}

接下来,定义以下 DTO,它将代替您的 List&lt;Day&gt; 进行序列化:

public class DayListDTO
{
    [XmlIgnore]
    public Day [] Days { get; set; }

    [XmlChoiceIdentifier(nameof(DayListDTO.Days))]
    [XmlElement(nameof(Day.Monday), typeof(object))]
    [XmlElement(nameof(Day.Tuesday), typeof(object))]
    [XmlElement(nameof(Day.Wednesday), typeof(object))]
    [XmlElement(nameof(Day.Thursday), typeof(object))]
    [XmlElement(nameof(Day.Friday), typeof(object))]
    [XmlElement(nameof(Day.Saturday), typeof(object))]
    [XmlElement(nameof(Day.Sunday), typeof(object))]
    public object[] DaysObjects
    {
        get
        {
            return Days == null ? null : Enumerable.Repeat(new object(), Days.Length).ToArray();
        }
        set
        {
            // Do nothing
        }
    }

    public static implicit operator DayListDTO(List<Day> list)
    {
        return list == null ? null : new DayListDTO { Days = list.ToArray() };
    }

    public static implicit operator List<Day>(DayListDTO dayList)
    {
        return dayList?.Days?.ToList() ?? new List<Day>();
    }
}

最后,通过向包含类添加代理属性来使用 DTO,如下所示:

public class StringArray
{
    [XmlIgnore]
    public List<Day> Days { get; set; }

    [XmlElement("Days")]
    public DayListDTO XmlDaysSurrogate { get { return Days; } set { Days = value; } }
}

在序列化时会生成以下 XML:

<StringArray xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <Days>
    <Monday />
    <Tuesday />
    <Wednesday />
  </Days>
</StringArray>

注意事项:

  • 要将XmlChoiceIdentifier 与数组正确使用,包含的 DTO 类型必须有 两个 数组成员:

    1. 一个数组,记录了选择元素的内容,这里是DayListDTO.DaysObjects
    2. 一个数组,记录选择元素的名称,这里是DayListDTO.Days,与第一个数组一一对应。


    由于与您的枚举列表对应的元素根本不包含任何内容,因此会为第一个数组返回一个由 object 项组成的虚拟数组。

  • 使用XmlChoiceIdentifier 可以保证xsd.exe 为您的类型自动生成的模式将正确指示正确命名的选择元素的无限序列。其他解决方案,例如在List&lt;Day&gt; 的某些子类上通过IXmlSerializable 实现自定义序列化,则没有这个优势。

工作样本小提琴here

【讨论】:

  • @RajendraRathore - 很高兴为您提供帮助。如果问题得到解决,请联系mark it as such
【解决方案2】:

尝试以下:

using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
using System.IO;

namespace ConsoleApplication1
{
    class Program
    {
        const string FILENAME = @"c:\temp\test.xml";
        static void Main(string[] args)
        {
            string xml = File.ReadAllText(FILENAME);

            XDocument doc = XDocument.Parse(xml);

            List<XElement> strings = doc.Descendants("string").ToList();

            foreach (XElement xelement in strings)
            {
                xelement.ReplaceWith(new XElement((string)xelement));
            }
        }
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-08
    • 2018-05-11
    • 1970-01-01
    • 2015-10-25
    • 1970-01-01
    • 2011-02-10
    相关资源
    最近更新 更多