Decidir qué propiedades se serializan en tiempo de ejecución

Supongamos que tengo que serializar un objeto de un auto de clase en niveles, p. Interno y Público. Algunas de las propiedades en el nivel público no se deben serializar, ya que son internas.

En este momento, la forma más fácil en la que puedo pensar para lograr esto es mediante el uso de la herencia:

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

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

Entonces podría

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

El resultado de ToSerialize () es tomado por un marco (no tengo control) y se serializa a JSON o XML.

Omití los atributos de serialización XML por simplicidad.

Esto se siente como un hack y los hacks te llevan muy lejos. ¿Hay una mejor manera (formas) de lograr esto?

Creo que ya está claro, pero me gustaría evitar escribir mis propios métodos de serialización para JSON y XML.

Gracias de antemano Tymek

== EDITAR

Para aclarar, quiero poder serializar múltiples niveles:

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

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;
}

== Enfoque elegido

arqué la respuesta de Marc Gravell como la respuesta, ya que proporciona la información genérica de cómo C # y sus componentes 'estándar' respaldan lo que pedí.

Sin embargo, creo que el mejor enfoque para mi problema es usar clases proxy como se muestra arriba y hacer que la clase se serialice en este patrón de niveles múltiples con métodos como se muestra a continuación.

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

Esto permite mantener el Car0..3 clases muy simples, con solo propiedades, para mantener y comprender.

Respuestas a la pregunta(4)

Su respuesta a la pregunta