Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Overriding a property with an attribute

I'm trying to find a way to change the serialization behavior of a property.

Lets say I have a situation like this:

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

   // other useful properties ...
}

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

   // other useful properties ...
}

Now I want to serialize EmployeeRecord. I don't want the LastUpdated property from the Record class to be serialized. (I do want LastUpdated to be serialized when I serialize Record, though).

First I tried hiding the LastUpdated property by using the new keyword and then adding the XmlIgnore attribute:

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

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

But that didn't work. Then I tried making the base LastUpdated virtual and overriding it, keeping the attribute:

[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 ...
}

This didn't work either. In both attempts the LastUpdated ignored the XmlIgnore attribute and happily went about its business of serializing.

Is there a way to make what I'm trying to do happen?

like image 907
Sailing Judo Avatar asked Feb 26 '09 22:02

Sailing Judo


People also ask

Can attributes be overridden?

The operator view policy can override values of attributes in a smart tag, except for the common VTF attributes var , type and format . You dynamically change the attribute values in real time in response to conditions specified in a policy.

Can we override properties in Java?

You cannot "override" fields, because only methods can have overrides (and they are not allowed to be static or private for that).

How do I add attributes to my property at runtime?

It is not possible to add Attributes in run-time. Attributes are static and cannot be added or removed.


2 Answers

First, the [Serializable] attr has nothing to do with the XmlSerializer. That is a red herring. [Serializable] is meaningful to System.Runtime.Serialization, while the XmlSerializer lives in System.Xml.Serialization. If you are decorating your class with [Serializable] and your members with [XmlIgnore] then you are probably confusing yourself or other readers of your code.

XmlSerialization in .NET is very flexible. Depending on how the serialization is being done, directly by you or indirectly, let's say by the web services runtime - you have different ways to control things.

One option is to use the propertyNameSpecified pattern to turn ON or OFF the property in XML Serialization. Suppose you have this code:

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

Then, if LastModifiedSpecified is false in an instance, the LastModified field will not be serialized for that instance. In the constructor for your type, you can set LastModifiedSpecified to always be true in the base type, and always false in the derived type. The actual boolean - LastModifiedSpecified - never gets serialized because it is marked XmlIgnore.

This little trick is documented here.

Your other option is to use XmlAttributeOverrides, which is a way of dynamically providing the set of XML serialization attributes (like XmlElementAttribute, XmlIgnoreAttribute, XmlRootAttribute, and so on...) - dynamically providing those attributes to the serializer at runtime. The XmlSerializer, instead of inspecting the type itself for those attributes, will just walk through the list of override attributes provided to its constructor.

    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.

This is illustrated in more detail here.

In your case, you would provide an XmlIgnoreAttribute as an override, but only when serializing the derived type. (or whatever) This works only when you directly instantiate the XmlSerializer - it won't work when serialization is done implicitly by the runtime, as with web services.

Cheers!

like image 120
Cheeso Avatar answered Sep 21 '22 12:09

Cheeso


The best I can think of...

[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 ...
}

Basically, there are a few patterns that XmlSerializer respects; public bool ShouldSerialize*(), and public bool *Specified {get;set;} (note you should mark *Specified with [XmlIgnore] too...).

Not very elegant, I'll grant; but XmlSerializer only looks at public members, so you can't even hide them (short of [EditorBrowsable(EditorBrowsableState.Never), Browsable(false)]).

like image 43
Marc Gravell Avatar answered Sep 19 '22 12:09

Marc Gravell