views:

1553

answers:

3

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?

+1  A: 

You may need to implement the ISerializable interface and explicitly provide serialization data if you want that sort of degree of control.

Snarfblam
+5  A: 

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!

Cheeso
Wow, I'd never even heard of the Specified pattern before. Worked like a charm!
Sailing Judo
+4  A: 

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

Marc Gravell