代码之家  ›  专栏  ›  技术社区  ›  Mykhailo Seniutovych

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

  •  2
  • Mykhailo Seniutovych  · 技术社区  · 6 年前

    我正在使用 XmlSerializer 将C对象序列化为XML。我有 DefaultValueAttribute 在我试图序列化的类的某些属性上,当我试图序列化它们时,似乎 XML序列化程序 如果值等于默认值,则不在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(注意名称属性不可用):

    <?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" />
    

    我无法修改类的源代码,因此无法删除 默认值属性 。有办法吗 XML序列化程序 是否在不更改源代码的情况下序列化此属性?

    1 回复  |  直到 6 年前
        1
  •  3
  •   steve16351    6 年前

    你可以通过传递 XmlAttributeOverrides 实例到 XmlSerializer 当你创建它如下。您可以使用它将默认值更改为其他值,或者将其设置为空以有效地删除它。

    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);