Замена свойства атрибутом

Я пытаюсь найти способ изменить поведение сериализации свойства.

Допустим, у меня такая ситуация:

[Serializable]
public class Record
{
   public DateTime LastUpdated {get; set; }

   // other useful properties ...
}

public class EmployeeRecord : Record
{
   public string EmployeeName {get; set; }

   // other useful properties ...
}

Теперь я хочу сериализовать EmployeeRecord. Я не хочу, чтобы свойство LastUpdated из класса Record было сериализовано. (Я действительно хочу, чтобы LastUpdated был сериализован при сериализации Record).

Сначала я попытался скрыть свойство LastUpdated, используя ключевое слово new, а затем добавив атрибут XmlIgnore:

public class EmployeeRecord : Record
{
   public string EmployeeName {get; set; }

   [XmlIgnore]
   public new DateTime LastUpdated {get; set; }
   // other useful properties ...
}

Но это не сработало. Затем я попытался сделать базовый LastUpdated виртуальным и переопределить его, сохранив атрибут:

[Serializable]
public class Record
{
   public virtual DateTime LastUpdated {get; set; }

   // other useful properties ...
}

public class EmployeeRecord : Record
{
   public string EmployeeName {get; set; }

   [XmlIgnore]
   public override DateTime LastUpdated {get; set; }
   // other useful properties ...
}

Это тоже не сработало. В обеих попытках LastUpdated проигнорировал атрибут XmlIgnore и благополучно занялся сериализацией.

Есть ли способ реализовать то, что я пытаюсь сделать?

Ответов (2)

Решение

Во-первых, атрибут [Serializable] не имеет ничего общего с XmlSerializer. Это отвлекающий маневр. [Serializable] имеет значение для System.Runtime.Serialization, а XmlSerializer находится в System.Xml.Serialization. Если вы украшаете свой класс [Serializable], а ваши члены - [XmlIgnore], то вы, вероятно, сбиваете с толку себя или других читателей своего кода.

XmlSerialization в .NET очень гибок. В зависимости от того, как выполняется сериализация, прямо вами или косвенно, скажем, средой выполнения веб-сервисов, у вас есть разные способы управления вещами.

Один из вариантов - использовать шаблон propertyName Specified для включения или выключения свойства в сериализации XML. Предположим, у вас есть такой код:

public class TypeA
{ 
  public DateTime LastModified;
  [XmlIgnore]
  public bool LastModifiedSpecified;
}

Затем, если LastModifiedSpecified имеет значение false в экземпляре, поле LastModified не будет сериализовано для этого экземпляра. В конструкторе вашего типа вы можете установить LastModifiedSpecified, чтобы он всегда был истинным в базовом типе и всегда ложным в производном типе. Фактическое логическое значение - LastModifiedSpecified - никогда не сериализуется, потому что оно помечено как XmlIgnore.

Этот небольшой трюк задокументирован здесь .

Другой вариант - использовать XmlAttributeOverrides, который представляет собой способ динамического предоставления набора атрибутов сериализации XML (например, XmlElementAttribute, XmlIgnoreAttribute, XmlRootAttribute и т. Д.) - динамического предоставления этих атрибутов сериализатору во время выполнения. XmlSerializer вместо того, чтобы проверять сам тип на предмет наличия этих атрибутов, просто просматривает список переопределяемых атрибутов, предоставленных его конструктору.

    var overrides = new XmlAttributeOverrides();
    // ....fill the overrides here....
    // create a new instance of the serializer specifying overrides
    var s1 = new XmlSerializer(typeof(Foo), overrides);
    // serialize as normal, here.

Более подробно это проиллюстрировано здесь .

В вашем случае вы должны предоставить XmlIgnoreAttribute в качестве переопределения, но только при сериализации производного типа. (или что-то еще) Это работает только тогда, когда вы напрямую создаете экземпляр XmlSerializer - он не будет работать, если сериализация выполняется неявно средой выполнения, как в случае с веб-службами.

Ваше здоровье!

Лучшее, о чем я могу думать ...

[Serializable]
public class Record
{
   public DateTime LastUpdated {get; set; }
   public virtual bool ShouldSerializeLastUpdated() {return true;}
   // other useful properties ...
}

public class EmployeeRecord : Record
{
   public string EmployeeName {get; set; }
   public override bool ShouldSerializeLastUpdated() {return false;}
   // other useful properties ...
}

В принципе, есть несколько шаблонов, которые XmlSerializer уважают; public bool ShouldSerialize*() И public bool *Specified {get;set;} (обратите внимание , вы должны пометить *Specified с [XmlIgnore] тоже ...).

Не очень изящно, согласен; но XmlSerializer смотрит только на публичных участников, так что вы даже не можете их скрыть (за исключением [EditorBrowsable(EditorBrowsableState.Never), Browsable(false)] ).