Переопределение свойства с атрибутом

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

Давайте скажем, что у меня такая ситуация:

[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, используя новое ключевое слово, а затем добавив атрибут 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 и с радостью продолжил свою сериализацию.

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

Ответ 1

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

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

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

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

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

Ура!

Ответ 2

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

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

Ответ 3

Возможно, вам понадобится реализовать интерфейс ISerializable и явно предоставить данные о сериализации, если вы хотите иметь такую ​​степень контроля.