繁体   English   中英

如何使用 XmlSerializer 使用 DefaultValueAttribute 序列化属性?

[英]How to serialize properties with DefaultValueAttribute using XmlSerializer?

我正在使用XmlSerializer将 C# 对象序列化为 XML。我在尝试序列化的类的某些属性上有DefaultValueAttribute ,当我尝试序列化它们时,如果XmlSerializer等于默认值,它似乎不包含 xml 中的值。 看这个例子:

using System.IO;
using System.Xml;
using System.Xml.Serialization;

namespace Test
{
    public class Person
    {
        [System.Xml.Serialization.XmlAttribute()]
        [System.ComponentModel.DefaultValue("John")]
        public string Name { get; set; }
    }

    public static class Test
    {
        public static void Main()
        {
            var serializer = new XmlSerializer(typeof(Person));
            var person = new Person { Name = "John" };

            using (var sw = new StringWriter())
            {
                using (var writer = XmlWriter.Create(sw))
                {
                    serializer.Serialize(writer, person);
                    var xml = sw.ToString();
                }
            }
        }
    }
}

会产生如下xml(注意name属性不可用):

<?xml version="1.0" encoding="utf-16"?>
<Person xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" />

我不能修改类的源代码,所以我不能删除DefaultValueAttribute 有没有办法让XmlSerializer在不更改源代码的情况下序列化这些属性?

可以通过如下创建时将XmlAttributeOverrides实例传递给XmlSerializer来实现。 您可以使用此选项将默认值更改为其他值,或将其设置为null以有效地将其删除。

XmlAttributeOverrides attributeOverrides = new XmlAttributeOverrides();

var attributes = new XmlAttributes()
{
    XmlDefaultValue = null,
    XmlAttribute = new XmlAttributeAttribute()
};

attributeOverrides.Add(typeof(Person), "Name", attributes);

var serializer = new XmlSerializer(typeof(Person), attributeOverrides);
var person = new Person { Name = "John" };

using (var sw = new StringWriter())
{
    using (var writer = XmlWriter.Create(sw))
    {
        serializer.Serialize(writer, person);
        var xml = sw.ToString();
    }
}

更新:以上意味着您必须在要更改的每个属性上再次提供其他不相关的属性。 如果您有很多属性,并且只想删除所有属性的默认属性,那么这会有些麻烦。 下面的类可用于保留其他自定义属性,而仅删除一种类型的属性。 如果需要仅针对某些属性等,可以对其进行进一步扩展。

public class XmlAttributeOverrideGenerator<T>
{
    private static XmlAttributeOverrides _overrides;
    private static Type[] _ignoreAttributes = new Type[] { typeof(DefaultValueAttribute) };

    static XmlAttributeOverrideGenerator()
    {
        _overrides = Generate();
    }

    public static XmlAttributeOverrides Get()
    {
        return _overrides;
    }

    private static XmlAttributeOverrides Generate()
    {
        var xmlAttributeOverrides = new XmlAttributeOverrides();

        Type targetType = typeof(T);
        foreach (var property in targetType.GetProperties())
        {
            XmlAttributes propertyAttributes = new XmlAttributes(new CustomAttribProvider(property, _ignoreAttributes));
            xmlAttributeOverrides.Add(targetType, property.Name, propertyAttributes);
        }

        return xmlAttributeOverrides;
    }

    public class CustomAttribProvider : ICustomAttributeProvider
    {
        private PropertyInfo _prop = null;
        private Type[] _ignoreTypes = null;            

        public CustomAttribProvider(PropertyInfo property, params Type[] ignoreTypes)
        {
            _ignoreTypes = ignoreTypes;
            _prop = property;
        }

        public object[] GetCustomAttributes(bool inherit)
        {
            var attribs = _prop.GetCustomAttributes(inherit);
            if (_ignoreTypes == null) return attribs;
            return attribs.Where(attrib => IsAllowedType(attrib)).ToArray();
        }

        private bool IsAllowedType(object attribute)
        {
            if (_ignoreTypes == null) return true;
            foreach (Type type in _ignoreTypes)
                if (attribute.GetType() == type)
                    return false;

            return true;
        }

        public object[] GetCustomAttributes(Type attributeType, bool inherit)
        {
            throw new NotImplementedException();
        }

        public bool IsDefined(Type attributeType, bool inherit)
        {
            throw new NotImplementedException();
        }
    }
}

用法:

XmlAttributeOverrides attributeOverrides = XmlAttributeOverrideGenerator<Person>.Get();            
var serializer = new XmlSerializer(typeof(Person), attributeOverrides);

我没有足够的声誉来评论 steve16351 的回答。 但我觉得我对他的代码做了一点改进。

我的用例涉及通过 Microsoft 提供的 XSD.exe 生成的 XML 模式文件,然后从模式文件生成 class。 因此 class 具有架构中的所有 DefaultValue 标签。 还创建了许多嵌套类型。 因此,为了使我的代码简洁,我修改了“生成”方法以获取顶层 class 及其下方的所有覆盖。 然后所有内容都在单个 XmlAttributesOverrides object 中返回。

static XmlAttributeOverrideGenerator()
{
    _overrides = Generate(typeof(T), new XmlAttributeOverrides());
}

private static XmlAttributeOverrides Generate(Type targetType, XmlAttributeOverrides Overrides)
{
    foreach (var property in targetType.GetProperties())
    {
        if (property.CustomAttributes.Any( CA => CA.AttributeType == typeof(DefaultValueAttribute)))
        {
            XmlAttributes propertyAttributes = new XmlAttributes(new CustomAttribProvider(property, _ignoreAttributes));
            Overrides.Add(targetType, property.Name, propertyAttributes);
        }
        else
        {
            Type propType = property.PropertyType;
            if (propType.IsClass && !propType.IsValueType && !propType.IsEnum && !propType.IsPrimitive && !propType.IsSealed)  // Check if this is a custom class
            {
                //If this is a nested class or other class type, generate its overrides as well
                Generate(propType, Overrides);
            }
        }
    }

    return Overrides;
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM