如何让 XmlSerializer 忽略某种类型的所有成员?

How to get XmlSerializer to ignore all members of a certain type?

我想将 XML 反序列化为以下内容 class:

public partial class Delivery
{
    public System.Nullable<System.DateTime> sentDate { get; set; }
    public System.Nullable<System.DateTime> receivedDate { get; set; }
    public System.Nullable<System.DateTime> responseDueDate { get; set; }
}

但是,XML 中的日期不是 XmlSerializer 友好格式。根据对多个问题的回答,我添加了这个 class:

public partial class DateSafeDelivery : Delivery
{
    [XmlElement("sentDate")]
    public string sentDateString
    {
        internal get { return sentDate.HasValue ? XmlConvert.ToString(sentDate.Value) : null; }
        set { sentDate = DateTime.Parse(value); }
    }
    [XmlElement("receivedDate")]
    public string receivedDateString
    {
        internal get { return receivedDate.HasValue ? XmlConvert.ToString(receivedDate.Value) : null; }
        set { receivedDate = DateTime.Parse(value); }
    }
    [XmlElement("responseDueDate")]
    public string responseDueDateString
    {
        internal get { return responseDueDate.HasValue ? XmlConvert.ToString(responseDueDate.Value) : null; }
        set { responseDueDate = DateTime.Parse(value); }
    }
}

然后我配置覆盖:

private static XmlAttributeOverrides GetOverrides()
{
    var overrides = new XmlAttributeOverrides();
    var attributes = new XmlAttributes();
    attributes.XmlElements.Add(new XmlElementAttribute(typeof(DateSafeDelivery)));
    overrides.Add(typeof(MyParent), "Delivery", attributes);
    var ignore = new XmlAttributes { XmlIgnore = true };
    overrides.Add(typeof(DateTime?), ignore);
    return overrides;
}

这导致以下预期:

Message=The string '2010-06-12T00:00:00 -05:00' is not a valid AllXsd value.
Source=System.Xml.ReaderWriter
StackTrace:
    at System.Xml.Schema.XsdDateTime..ctor(String text, XsdDateTimeFlags kinds)
    at System.Xml.XmlConvert.ToDateTime(String s, XmlDateTimeSerializationMode dateTimeOption)
    at Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationReaderDeserializedAudit.Read1_NullableOfDateTime(Boolean checkType)
    at Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationReaderDeserializedAudit.Read15_DateSafeDelivery(Boolean isNullable, Boolean checkType)
    at Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationReaderDeserializedAudit.Read16_MyParent(Boolean isNullable, Boolean checkType)

所以 DateSafeDelivery 被使用了,但是日期的 XmlIgnore 被忽略了。

它会工作,如果我切换:

    overrides.Add(typeof(DateTime?), ignore);

与:

    new Dictionary<string, Type>()
    {
        { "sentDate", typeof(Delivery) },
        { "receivedDate", typeof(Delivery) },
        { "responseDueDate", typeof(Delivery) },
    }
        .ToList()
        .ForEach(t1 => overrides.Add(t1.Value, t1.Key, ignore));

一处 class 和三处房产都可以。但是我有 14 classes,总共有三打日期属性。我知道我必须为 14 classes 添加覆盖,但是有没有办法让序列化程序忽略所有 DateTime 属性?

我认为 XmlAttributeOverrides.Add Method (Type, XmlAttributes) 会做到。但它不起作用。为什么?这个方法是做什么用的?它有什么作用?

XmlAttributeOverrides.Add(Type, XmlAttributes) is designed to add an XML override attribute to the type itself, rather than to all properties returning values of that type. E.g. if you wanted to add an [XmlRoot("OverrideName")] 属性到 DateSafeDelivery,你可以这样做:

overrides.Add(typeof(DateSafeDelivery),
    new XmlAttributes { XmlRoot = new XmlRootAttribute("OverrideName") });

没有动态覆盖属性忽略返回给定类型的所有属性,因为没有 static XML serialization attribute that can suppress serialization of all properties of a given type. The following does not even compile, because [XmlIgnore] 只能应用于 属性 或字段:

[XmlIgnore] public class IgnoreAllInstancesOfMe { } // Fails to compile.

(至于为什么 Microsoft 没有实现对应用于类型的 [XmlIgnore] 的支持 - 你需要问他们。)

因此您需要引入如下扩展方法:

public static partial class XmlAttributeOverridesExtensions
{
    public static XmlAttributeOverrides IgnorePropertiesOfType(this XmlAttributeOverrides overrides, Type declaringType, Type propertyType)
    {
        return overrides.IgnorePropertiesOfType(declaringType, propertyType, new HashSet<Type>());
    }

    public static XmlAttributeOverrides IgnorePropertiesOfType(this XmlAttributeOverrides overrides, Type declaringType, Type propertyType, HashSet<Type> completedTypes)
    {
        if (overrides == null || declaringType == null || propertyType == null || completedTypes == null)
            throw new ArgumentNullException();
        XmlAttributes attributes = null;
        for (; declaringType != null && declaringType != typeof(object); declaringType = declaringType.BaseType)
        {
            // Avoid duplicate overrides.
            if (!completedTypes.Add(declaringType))
                break;
            foreach (var property in declaringType.GetProperties(BindingFlags.Public | BindingFlags.DeclaredOnly | BindingFlags.Instance))
            {
                if (property.PropertyType == propertyType || Nullable.GetUnderlyingType(property.PropertyType) == propertyType)
                {
                    attributes = attributes ?? new XmlAttributes { XmlIgnore = true };
                    overrides.Add(declaringType, property.Name, attributes);
                }
            }
        }
        return overrides;
    }
}

然后做:

    private static XmlAttributeOverrides GetOverrides()
    {
        var overrides = new XmlAttributeOverrides();

        var attributes = new XmlAttributes();
        attributes.XmlElements.Add(new XmlElementAttribute(typeof(DateSafeDelivery)));
        overrides.Add(typeof(MyParent), "Delivery", attributes);

        // Ignore all DateTime properties in DateSafeDelivery
        var completed = new HashSet<Type>();
        overrides.IgnorePropertiesOfType(typeof(DateSafeDelivery), typeof(DateTime), completed);
        // Add the other 14 types as required

        return overrides;
    }

另请注意 DateSafeDelivery 上的 DateString 属性必须具有 public get 和 set 方法,例如:

public partial class DateSafeDelivery : Delivery
{
    [XmlElement("sentDate")]
    public string sentDateString
    {
        get { return sentDate.HasValue ? XmlConvert.ToString(sentDate.Value, XmlDateTimeSerializationMode.Utc) : null; }
        set { sentDate = DateTime.Parse(value); }
    }

XmlSerializer 无法序列化不完全 public.

的 属性

顺便说一下,请注意您必须静态缓存任何使用覆盖构造的 XmlSerializer 以避免严重的内存泄漏,如 this answer.

中所述