为什么我必须使用*指定属性来强制序列化?有没有办法不这样做

本文关键字:序列化 有没有 这样做 属性 为什么 | 更新日期: 2023-09-27 18:02:27

我在我的项目中使用xml序列化来基于xml模式序列化和反序列化对象。我使用xsd工具创建在序列化/反序列化对象时使用的类。

当我在发送之前序列化对象时,我被迫将*指定属性设置为true,以强制序列化器序列化所有非string类型的属性。

是否有一种方法可以强制序列化所有属性,而不必将*指定的属性设置为true?

为什么我必须使用*指定属性来强制序列化?有没有办法不这样做

FooSpecified属性用于控制是否序列化Foo属性。如果您总是想序列化属性,只需删除FooSpecified属性。

我知道这是一个古老的问题,但是当您将代码作为构建的一部分生成,并且您的.xsd可能在单个发布周期内更改多次时,其他答案(可能除了使用Xsd2Code的建议)都没有真正产生理想的解决方案。

对我来说,获得我真正想要的并且仍然使用xsd.exe的一个简单方法是通过一个简单的后处理器运行生成的文件。后处理器的代码如下:

namespace XsdAutoSpecify
{
using System;
using System.Collections.Generic;
using System.IO;
using System.Text.RegularExpressions;
class Program
{
    static void Main(string[] args)
    {
        try
        {
            if (args.Length != 1)
            {
                throw new ArgumentException("Specify a file name");
            }
            string fileName = args[0];
            Regex regex = new Regex(".*private bool (?<fieldName>.*)Specified;");
            IList<string> result = new List<string>();
            IDictionary<string, string> edits = new Dictionary<string, string>();
            foreach (string line in File.ReadLines(fileName))
            {
                result.Add(line);
                if (line.Contains("public partial class"))
                {
                    // Don't pollute other classes which may contain like-named fields
                    edits.Clear();
                }
                else if (regex.IsMatch(line))
                {
                    // We found a "private bool fooSpecified;" line.  Add
                    // an entry to our edit dictionary.
                    string fieldName = regex.Match(line).Groups["fieldName"].Value;
                    string lineToAppend = string.Format("this.{0} = value;", fieldName);
                    string newLine = string.Format("                this.{0}Specified = true;", fieldName);
                    edits[lineToAppend] = newLine;
                }
                else if (edits.ContainsKey(line.Trim()))
                {
                    // Use our edit dictionary to add an autospecifier to the foo setter, as follows:
                    //   set {
                    //       this.fooField = value;
                    //       this.fooFieldSpecified = true;
                    //   }
                    result.Add(edits[line.Trim()]);
                }
            }
            // Overwrite the result
            File.WriteAllLines(fileName, result);
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.ToString());
            Environment.Exit(-1);
        }
    }
}
}

生成的结果类似于以下代码:

    [System.Xml.Serialization.XmlAttributeAttribute()]
    public barEnum foo {
        get {
            return this.fooField;
        }
        set {
            this.fooField = value;
            this.fooFieldSpecified = true;
        }
    }

您可以为您的模式添加一个默认值,然后使用DefaultValueAttribute。

例如,您的模式中可以有以下内容:

<xs:element name="color" type="xs:string" default="red"/>

然后是以下序列化属性:

[DefaultValue(red)]
public string color { get; set; }

如果color属性没有被显式地设置为其他值,这将强制它始终序列化为"red"。

我遇到了同样的问题,最终通过反射将所有*指定的属性设置为true。

var customer = new Customer();
foreach (var propertyInfo in typeof(Customer).GetProperties().Where(p => p.Name.EndsWith("Specified")))
{
    propertyInfo.SetValue(customer, true);
}

我们发现这个问题的答案是确保模式元素都定义为string数据类型。这将确保序列化器序列化所有字段而不使用相关的*指定属性。