2017-02-21 2 views
3

Je veux désérialiser XML dans la classe suivante:Comment faire pour que XmlSerializer ignore tous les membres d'un certain type?

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

Cependant, les dates du XML ne sont pas dans un format convivial XmlSerializer. Sur la base des réponses aux questions mulitple, j'ai ajouté cette classe:

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

je configure alors mes remplacements:

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

Il en résulte la expection suivante:

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) 

Alors DateSafeDelivery est d'être utilisé, mais le XmlIgnore pour les dates est, bien, ignoré.

Il fonctionnera, si je passe:

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

avec:

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

Et c'est très bien pour une classe et trois propriétés. Mais j'ai 14 classes avec un total de trois douzaines de propriétés de date. Je sais que je dois ajouter des remplacements pour les 14 classes, mais est-il possible d'obtenir que le sérialiseur ignore toutes les propriétés DateTime? Je pensais XmlAttributeOverrides.Add Method (Type, XmlAttributes) le ferait. Mais ça ne marche pas. Pourquoi? À quoi sert cette méthode? Qu'est ce que ça fait?

Répondre

1

XmlAttributeOverrides.Add(Type, XmlAttributes) est conçu pour ajouter un attribut de substitution XML au type lui-même, plutôt qu'à toutes les propriétés renvoyant des valeurs de ce type. Par exemple. si vous voulez ajouter un attribut [XmlRoot("OverrideName")]-DateSafeDelivery, vous pouvez faire quelque chose comme:

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

Il n'y a pas override dynamique attribut ignorer toutes les propriétés renvoyant un type donné parce qu'il n'y a pas static XML serialization attribute qui peut supprimer la sérialisation de toutes les propriétés d'un type donné. Ce qui suit ne même pas compiler, car [XmlIgnore] ne peut être appliqué à une propriété ou sur le terrain:

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

(. Quant à savoir pourquoi Microsoft n'a pas mis en œuvre un soutien pour [XmlIgnore] appliqué à un type - vous devez leur demander)

vous donc besoin d'introduire une méthode d'extension comme ce qui suit:

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

Et faire:

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

S'il vous plaît noter également que les DateString propriétés sur DateSafeDelivery doivent avoir publics méthodes get et set, par exemple .:

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 ne peut pas sérialiser une propriété qui ne sont pas entièrement public.Incidemment, notez que vous devez mettre en antémémoire tout XmlSerializer construit avec des remplacements pour éviter une fuite de mémoire importante, comme expliqué dans this answer. XmlAttributeOverrides.Add (Type, XmlAttributes) est donc uniquement pour le type en cours de désérialisation.

+1

Je l'ai. En fin de compte, j'ai répertorié chaque propriété dans le code. Je réfléchissais à la réflexion, mais je ne voulais pas que l'ordinateur comprenne à chaque fois ce que je pourrais prendre 3 minutes pour le dire. En outre, j'ai vu des réponses sur la fuite de mémoire et j'utilise XmlSerializer statiquement. Et les get internes travaillent pour la désérialisation. C'est la seule direction qui m'intéresse pour cette classe. Merci. –