将可空类型序列化为可选的非可贵元素

Jac*_*esB 5 .net xml-serialization

我有一个带有可选元素(minOccurs=0,maxOccurs=1)类型的xsd模式int.元素未定义为可为空.在数据模型中,我想将其映射到.net类型的字段Nullable<int>,其中null值应对应于xml中省略的元素.

但是,使用XmlSerializer,似乎我必须在数据模型中声明一个可为空的字段[XmlElement IsNullable=true].如果我设置IsNullable=false,我得到异常" 对于Nullable类型,IsNullable可能不会被设置为'false'."对于Nullable类型,IsNullable可能不会设置为'false'.考虑使用'System.Int32'类型或从XmlElement属性中删除IsNullable属性."但是如果我理解正确的话,设置IsNullable=true(或保留属性)会隐式地将元素设置为nillable,从而改变模式.

这是架构优先设计,所以我不能只将'nillable'添加到架构中的元素.

如何将可空的.net类型映射到不可为空的xml元素?

(我知道在使用数据模型中的XxxSpecified属性序列化到xml时我可以省略nil-elements,但据我所知,这种方法仍然需要向xsd模式添加nillable.)

编辑:感谢评论,我现在更好地理解问题.实际上有两个不同的问题:

  1. 如果架构元素不可为空(即使它是可选的),xsd.exe之类的架构到代码生成器会在生成的模型中创建一个不可为空的类型.我可以覆盖它(使用任何已知的代码生成器),因此我在生成的代码中获得可以为空的类型吗?

  2. XmlSerializer需要数据模型中的可空类型 [XmlElement IsNullable=true],这意味着模型隐式地将"nillable"添加到模式.我可以避免这个吗?

Ale*_*tin 5

我前段时间也遇到过这个问题.我通过引入处理序列化逻辑的附加属性来解决它.

  1. 首先,使用[XmlIgnore]属性标记原始属性,以将其从序列化/反序列化中排除.

    // Mark your original property from serialization/deserialization logic
    [XmlIgnore]
    public int? OriginalProperty { get; set; }
    
    Run Code Online (Sandbox Code Playgroud)
  2. 然后添加附加属性并使用[XmlElement("YourElementName")]属性标记它以处理序列化逻辑.

    // Move serialization logic to additional string property
    [XmlElement("OriginalPropertyXmlElement")]
    public string OriginalPropertyAsString
    {
        get
        {
            //...
        }
        set
        {
            //...
        }
    }
    
    Run Code Online (Sandbox Code Playgroud)
  3. 关于反序列化,它将:

    set
    {
        // Check the field existence in xml
        if (string.IsNullOrEmpty(value))
        {
            // Set the original property to null
            this.OriginalProperty = default(int?);
        }
        else
        {
            // Get value from xml field
            this.OriginalProperty = int.Parse(value);
        }
    }
    
    Run Code Online (Sandbox Code Playgroud)
  4. 在序列化:

    get
    {
        if (this.OriginalProperty.HasValue)
        {
            // Serialize it
            return this.OriginalProperty.ToString();
        }
        else
        {
            // Don't serialize it
            return null;
        }
    }
    
    Run Code Online (Sandbox Code Playgroud)
  5. 示例可能如下所示:

    [XmlRoot("scene")]
    public class Scene
    {
        [XmlIgnore]
        public int? ParentId { get; set; }
    
        [XmlElement("parent_id")]
        public string ParentIdAsString
        {
            get
            {
                return this.ParentId.HasValue ? this.ParentId.ToString() : null;
            }
    
            set
            {
                this.ParentId = !string.IsNullOrEmpty(value) ? int.Parse(value) : default(int?);
            }
        }
    }
    
    Run Code Online (Sandbox Code Playgroud)

它非常简单,您不必编写自己的序列化程序,也不必破解xsd或其他东西.