【问题标题】:How to get XmlSerializer to ignore all members of a certain type?如何让 XmlSerializer 忽略某种类型的所有成员?
【发布时间】:2017-02-21 19:51:58
【问题描述】:

我想将 XML 反序列化为以下类:

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 友好格式。根据对多个问题的回答,我添加了这个类:

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

这对于一个类和三个属性来说很好。但是我有 14 个类,总共有三打日期属性。我知道我必须为 14 个类添加覆盖,但是有没有办法让序列化程序忽略所有 DateTime 属性?

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

【问题讨论】:

    标签: c# .net xml-serialization xmlserializer


    【解决方案1】:

    XmlAttributeOverrides.Add(Type, XmlAttributes) 旨在将 XML 覆盖属性添加到类型本身,而不是添加到返回该类型的所有属性值。例如。如果您想将[XmlRoot("OverrideName")] 属性添加到DateSafeDelivery,您可以执行以下操作:

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

    没有动态覆盖属性来忽略所有返回给定类型的属性,因为没有static XML serialization attribute 可以抑制给定类型的所有属性的序列化。以下甚至无法编译,因为[XmlIgnore] 只能应用于属性或字段:

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

    (至于微软为什么不支持应用于类型的[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 无法序列化未完全公开的属性。

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

    【讨论】:

    • 所以 XmlAttributeOverrides.Add(Type, XmlAttributes) 仅适用于被反序列化的类型。知道了。最后,我列出了代码中的每个属性。我考虑过反思,但不想让计算机每次都弄清楚我可以花 3 分钟告诉它什么。此外,我确实看到了有关内存泄漏的答案,并且正在静态使用 XmlSerializer。内部获取正在反序列化。这是我在这门课上唯一关心的方向。谢谢。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-09-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-08-05
    • 1970-01-01
    相关资源
    最近更新 更多