Переопределение свойства с помощью атрибута - PullRequest
10 голосов
/ 27 февраля 2009

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

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

[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 был сериализован при сериализации записи).

Сначала я попытался скрыть свойство 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 ]

17 голосов
/ 27 февраля 2009

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

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

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

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

Тогда, если LastModifiedSpecified имеет значение false в экземпляре, поле LastModified не будет сериализовано для этого экземпляра. В конструкторе для вашего типа вы можете установить LastModifiedSpecified, чтобы всегда быть true в базовом типе и всегда false в производном типе. Фактическое логическое значение - 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 - оно не будет работать, когда сериализация выполняется неявно во время выполнения, как с веб-сервисами.

Ура!

8 голосов
/ 27 февраля 2009

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

[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)]).

...