在 C# 中删除 XML 序列化的 DefaultValue 属性
Posted
技术标签:
【中文标题】在 C# 中删除 XML 序列化的 DefaultValue 属性【英文标题】:Remove DefaultValue attribute for XML serialization in C# 【发布时间】:2020-12-26 03:34:29 【问题描述】:我正在将一个对象序列化为 XML,该对象在某些属性上具有 DefaultValue
属性。在某些情况下,我想在序列化期间禁用所有这些默认值。有没有办法在运行时删除属性?
[Serializable]
[XmlType(TypeName = "MyType")]
public class MyType
public MyType()
MyValue = false;
[XmlElement(ElementName = "myValue", Form = XmlSchemaForm.Unqualified)]
[DefaultValue(false)]
public bool MyValue get; set;
public class TestSerializer
public void Serialize()
XmlSerializer serializer = new XmlSerializer(typeof(MyType));
using (TextWriter writer = new StreamWriter(stream, Encoding.UTF8, 1024, true))
serializer.Serialize(writer, new MyType());
我已经在考虑通过反射来实现这一点,但无法让它发挥作用。 XmlAttributeOverrides
似乎也没有帮助,但也许我还没有找到正确的方法。有什么想法吗?
【问题讨论】:
你看到Force XML serialization of XmlDefaultValue values了吗? This answer specifically 显示如何配置XmlAttributeOverrides
以禁用 [DefaultValue(false)]
属性。
【参考方案1】:
XmlSerializerIgnoringDefaultValuesKey.Create
从 this answer 到 Force XML serialization of XmlDefaultValue values 主要满足您的需求,但是您通过应用 [XmlElement(ElementName = "myValue", Form = XmlSchemaForm.Unqualified)]
覆盖了 MyValue
的 XML 元素名称,据说是未在该答案中实施:
使用此 XmlAttributes 对象覆盖时,任何希望保留的属性都需要转移到此新对象中。
以下增强版本支持转移[XmlElement]
、[XmlArray]
和[XmlArrayItem]
覆盖属性:
public abstract class XmlSerializerKey
static class XmlSerializerHashTable
static Dictionary<object, XmlSerializer> dict;
static XmlSerializerHashTable()
dict = new Dictionary<object, XmlSerializer>();
public static XmlSerializer GetSerializer(XmlSerializerKey key)
lock (dict)
XmlSerializer value;
if (!dict.TryGetValue(key, out value))
dict[key] = value = key.CreateSerializer();
return value;
readonly Type serializedType;
protected XmlSerializerKey(Type serializedType)
this.serializedType = serializedType;
public Type SerializedType get return serializedType;
public override bool Equals(object obj)
if (ReferenceEquals(this, obj))
return true;
else if (ReferenceEquals(null, obj))
return false;
if (GetType() != obj.GetType())
return false;
XmlSerializerKey other = (XmlSerializerKey)obj;
if (other.serializedType != serializedType)
return false;
return true;
public override int GetHashCode()
int code = 0;
if (serializedType != null)
code ^= serializedType.GetHashCode();
return code;
public override string ToString()
return string.Format(base.ToString() + ": for type: " + serializedType.ToString());
public XmlSerializer GetSerializer()
return XmlSerializerHashTable.GetSerializer(this);
protected abstract XmlSerializer CreateSerializer();
public abstract class XmlSerializerWithExtraTypesKey : XmlSerializerKey
static IEqualityComparer<HashSet<Type>> comparer;
readonly HashSet<Type> extraTypes = new HashSet<Type>();
static XmlSerializerWithExtraTypesKey()
comparer = HashSet<Type>.CreateSetComparer();
protected XmlSerializerWithExtraTypesKey(Type serializedType, IEnumerable<Type> extraTypes)
: base(serializedType)
if (extraTypes != null)
foreach (var type in extraTypes)
this.extraTypes.Add(type);
public Type[] ExtraTypes get return extraTypes.ToArray();
public override bool Equals(object obj)
if (!base.Equals(obj))
return false;
XmlSerializerWithExtraTypesKey other = (XmlSerializerWithExtraTypesKey)obj;
return comparer.Equals(this.extraTypes, other.extraTypes);
public override int GetHashCode()
int code = base.GetHashCode();
if (extraTypes != null)
code ^= comparer.GetHashCode(extraTypes);
return code;
public sealed class XmlSerializerIgnoringDefaultValuesKey : XmlSerializerWithExtraTypesKey
readonly XmlAttributeOverrides overrides;
private XmlSerializerIgnoringDefaultValuesKey(Type serializerType, IEnumerable<Type> ignoreDefaultTypes, XmlAttributeOverrides overrides)
: base(serializerType, ignoreDefaultTypes)
this.overrides = overrides;
public static XmlSerializerIgnoringDefaultValuesKey Create(Type serializerType, IEnumerable<Type> ignoreDefaultTypes, bool recurse)
XmlAttributeOverrides overrides;
Type [] typesWithOverrides;
CreateOverrideAttributes(ignoreDefaultTypes, recurse, out overrides, out typesWithOverrides);
return new XmlSerializerIgnoringDefaultValuesKey(serializerType, typesWithOverrides, overrides);
protected override XmlSerializer CreateSerializer()
var types = ExtraTypes;
if (types == null || types.Length < 1)
return new XmlSerializer(SerializedType);
return new XmlSerializer(SerializedType, overrides);
static void CreateOverrideAttributes(IEnumerable<Type> types, bool recurse, out XmlAttributeOverrides overrides, out Type[] typesWithOverrides)
HashSet<Type> visited = new HashSet<Type>();
HashSet<Type> withOverrides = new HashSet<Type>();
overrides = new XmlAttributeOverrides();
foreach (var type in types)
CreateOverrideAttributes(type, recurse, overrides, visited, withOverrides);
typesWithOverrides = withOverrides.ToArray();
static void AddOverride(XmlAttributeOverrides overrides, Type type, MemberInfo memberInfo)
var xmlElementAttr = memberInfo.GetCustomAttributes<XmlElementAttribute>();
var xmlArrayAttr = memberInfo.GetCustomAttribute<XmlArrayAttribute>();
var xmlArrayItemAttr = memberInfo.GetCustomAttributes<XmlArrayItemAttribute>();
var attrs = new XmlAttributes
XmlDefaultValue = null,
XmlArray = xmlArrayAttr,
;
foreach (var a in xmlElementAttr)
attrs.XmlElements.Add(a);
foreach (var a in xmlArrayItemAttr)
attrs.XmlArrayItems.Add(a);
overrides.Add(type, memberInfo.Name, attrs);
static void CreateOverrideAttributes(Type type, bool recurse, XmlAttributeOverrides overrides, HashSet<Type> visited, HashSet<Type> withOverrides)
if (type == null || type == typeof(object) || type.IsPrimitive || type == typeof(string) || visited.Contains(type))
return;
foreach (var property in type.GetProperties(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public))
if (overrides[type, property.Name] == null) // Check to see if overrides for this base type were already set.
if (Attribute.IsDefined(property, typeof(DefaultValueAttribute), true))
withOverrides.Add(type);
AddOverride(overrides, type, property);
foreach (var field in type.GetFields(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public))
if (overrides[type, field.Name] == null) // Check to see if overrides for this base type were already set.
if (Attribute.IsDefined(field, typeof(DefaultValueAttribute), true))
withOverrides.Add(type);
AddOverride(overrides, type, field);
visited.Add(type);
if (recurse)
var baseType = type.BaseType;
if (baseType != type)
CreateOverrideAttributes(baseType, recurse, overrides, visited, withOverrides);
并像这样使用它:
var serializer = XmlSerializerIgnoringDefaultValuesKey.Create(typeof(MyType), new[] typeof(MyType) , true).GetSerializer();
using (TextWriter writer = new StreamWriter(stream, Encoding.UTF8, 1024, true))
serializer.Serialize(writer, new MyType());
演示小提琴here.
【讨论】:
以上是关于在 C# 中删除 XML 序列化的 DefaultValue 属性的主要内容,如果未能解决你的问题,请参考以下文章