Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Deciding which properties are serialized at runtime

Let's suppose I have to serialize an object of a class Car in levels e.g. Internal and Public. Some of the properties in the Public level should not be serialized as they are internal.

At this moment the 'easiest' way I can think of to achieve this is by using inheritance:

class CarPublic {
  public int PropX {get;set}
}

class CarInternal: CarPublic {
  public string PropY {get;set}
}

Then I could

object ToSerialize() {
 CarInternal car = GetCar();
 if( level == Level.Public ) { 
    return car as CarPublic;
 } else {
     return car;
 }
}

The result of the ToSerialize() is taken by a framework (I don't have control over) and serialized to JSON or XML.

I omitted the XML serialization attributes for simplicity.

This feels like a hack and hacks take you only so far. Is there better way (ways?) to achieve this?

I think its clear by now, but I would like to avoid writing my own serialization methods for JSON and XML.

Thanks in advance Tymek

==EDIT

To clarify, I want to be able to serialize multiple levels:

class Car0 {
  public int PropA {get;set}
}

class Car1: Car0 {
  public string PropB {get;set}
}

class Car2: Car1 {
  public int PropC {get;set}
}

class Car3: Car2 {
  public string PropD {get;set}
}

and

object ToSerialize( Level level ) {
 Car3 car = GetCar();
 switch( level ) {
   case Level.Zero: return car as Car0;
   case Level.One: return car as Car1;
   case Level.Two: return car as Car3;
   case Level.Three: return car as Car4;
 }
 return null;
}

== Chosen approach

I marked Marc Gravell's answer as the answer, as it provides the generic information of how C# and it's 'standard' components support what I asked for.

However I think the best approach for my problem is to use proxy classes as shown above and have the class being serialized in this multi-level pattern with methods like shown below.

public interface ICar {
    Car0 As0();
    Car1 As1();
    Car2 As2();
    Car3 As3();
 ...
 }

This allows keeping the Car0..3 classes very simple, with only properties, to maintain and understand.

like image 653
tymtam Avatar asked Feb 14 '12 05:02

tymtam


1 Answers

This depends a lot on what serialization framework you are using. You mention xml and json - well, the first thing to note is that you can just decorate with:

[XmlIgnore]
public int PropX {get;set;}

or

[ScriptIgnore]
public int PropX {get;set;}

which XmlSerializer and JavascriptSerializer will respond to. If you need to make the decision on a per-instance basis, there is the ShouldSerialize* and *Specified patterns:

public bool ShouldSerializePropX() {
   // return true to serialize, false to omit
}

The above is a name-based pattern, that is used by XmlSerializer and others; it has a twin:

[XmlIgnore, Browsable(false)]
public bool PropXSpecified {
    get { /* return true to serialize, false to omit */ }
    set { /* can just drop this value - don't need to assign */ }
}

You don't need to do anything to wire them up - they work automatically.

Different serializers allow different patterns.

In addition, sometimes you can add things like [XmlIgnore] at runtime - for example via XmlAttributeOverrides, or the equivalent for any given serializer.

like image 79
Marc Gravell Avatar answered Nov 07 '22 12:11

Marc Gravell