c# - 在 C# 中删除 XML 序列化的 DefaultValue 属性
问题描述
我正在将一个对象序列化为 XML,该 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
似乎也没有帮助,但也许我还没有找到正确的方法。有任何想法吗?
解决方案
XmlSerializerIgnoringDefaultValuesKey.Create
从这个答案到Force XML serialization of XmlDefaultValue values主要是做你需要的,但是你已经通过 apply 覆盖了 XML 元素名称,MyValue
据说[XmlElement(ElementName = "myValue", Form = XmlSchemaForm.Unqualified)]
在那个答案中没有实现:
使用此 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());
}
演示小提琴在这里。
推荐阅读
- memory - 使用 Verilog 验证单端口 RAM
- python - Even when giving proper shape for slicing I am getting a weird shape
- java - Niimbot printer and Android Studio
- javascript - Google Books Thumbail not working in Image React Native
- r - 当 R 中一个日期大于另一个日期时生成条件
- regex - PCRE正则表达式:排除单词的最后一部分
- javascript - 如何通过移动手机从各个角度查看手机链接上托管的 3D 图片?
- ubuntu - 如何为我的 pi 用户添加文件夹的写入权限?
- css - 带有自动调整大小的尾随下划线的表头 CSS
- html - 当我尝试使用 flex 居中和对齐项目时出现对齐问题