How to tell XmlSerializer to serialize properties with [DefautValue(…)] always?

后端 未结 4 1546
孤街浪徒
孤街浪徒 2020-12-20 11:42

I am using DefaultValue attribute for the proper PropertyGrid behavior (it shows values different from default in bold). Now if I want to serialize

4条回答
  •  情歌与酒
    2020-12-20 12:17

    This behaviour of the XmlSerializer can can be overwritten with XmlAttributeOverrides

    I borrowed the idea from here:

    static public XmlAttributeOverrides GetDefaultValuesOverrides(Type type)
    {
        XmlAttributeOverrides explicitOverrides = new XmlAttributeOverrides();
    
        PropertyDescriptorCollection c = TypeDescriptor.GetProperties(type);
        foreach (PropertyDescriptor p in c)
        {
            AttributeCollection attributes = p.Attributes;
            DefaultValueAttribute defaultValue = (DefaultValueAttribute)attributes[typeof(DefaultValueAttribute)];
            XmlIgnoreAttribute noXML = (XmlIgnoreAttribute)attributes[typeof(XmlIgnoreAttribute)];
            XmlAttributeAttribute attribute = (XmlAttributeAttribute)attributes[typeof(XmlAttributeAttribute)];
    
            if ( defaultValue != null && noXML == null )
            {
                XmlAttributeAttribute xmlAttribute = new XmlAttributeAttribute(attribute.AttributeName);
                XmlAttributes xmlAttributes = new XmlAttributes();
                xmlAttributes.XmlAttribute = xmlAttribute;
                explicitOverrides.Add(userType, attribute.AttributeName, xmlAttributes);
            }
        }
        return explicitOverrides;
    }
    

    And made my self an an Attribute to decorate the classes which should emit the default values. If you want do this for all classes, I'm sure you can adapt the whole concept.

    Public Class EmitDefaultValuesAttribute
        Inherits Attribute
        Private Shared mCache As New Dictionary(Of Assembly, XmlAttributeOverrides)
    
        Public Shared Function GetOverrides(assembly As Assembly) As XmlAttributeOverrides
            If mCache.ContainsKey(assembly) Then Return mCache(assembly)
            Dim xmlOverrides As New XmlAttributeOverrides
            For Each t In assembly.GetTypes()
                If t.GetCustomAttributes(GetType(EmitDefaultValuesAttribute), True).Count > 0 Then
                    AddOverride(t, xmlOverrides)
                End If
            Next
            mCache.Add(assembly, xmlOverrides)
            Return xmlOverrides
        End Function
    
        Private Shared Sub AddOverride(t As Type, xmlOverrides As XmlAttributeOverrides)
            For Each prop In t.GetProperties()
                Dim defaultAttr = prop.GetCustomAttributes(GetType(DefaultValueAttribute), True).FirstOrDefault()
                Dim xmlAttr As XmlAttributeAttribute = prop.GetCustomAttributes(GetType(XmlAttributeAttribute), True).FirstOrDefault()
                If defaultAttr IsNot Nothing AndAlso xmlAttr IsNot Nothing Then
                    Dim attrs As New XmlAttributes '= {New XmlAttributeAttribute}
                    attrs.XmlAttribute = xmlAttr
                    ''overide.Add(t, xmlAttr.AttributeName, attrs)
                    xmlOverrides.Add(t, prop.Name, attrs)
                End If
            Next
        End Sub
    

    Because xsd.exe produces partial classes you can add this EmitDefaultValuesAttribute in seperate a file:

    
    Public MyClass
        Public Property SubClass() As MySubClass
    End Class
    
    
    Public MySubClass
    End Class
    

    Usage is as follows:

    Dim serializer As New XmlSerializer(GetType(MyClass), EmitDefaultValuesAttribute.GetOverrides(GetType(MyClass).Assembly))
    

提交回复
热议问题