2012-02-14 7 views
8

Supongamos que tengo que serializar un objeto de una clase Auto en niveles, p. Interno y público. Algunas de las propiedades en el nivel público no se deben serializar ya que son internas.Decidir qué propiedades se serializan en el tiempo de ejecución

En este momento el camino 'fácil' que se me ocurre 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 la ToSerialize() se toma por un marco (no tengo control ) y serializado a JSON o XML.

He omitido los atributos de serialización XML para simplificar.

Esto se siente como un truco y los piratas lo llevan tan lejos. ¿Hay una mejor manera (maneras) 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, yo quiero ser capaz de 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} 
} 

y

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

Marqué 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" admiten lo que solicité.

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

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

Esto permite mantener los Car0..3 clases muy simple, con sólo propiedades, para mantener y entender.

+1

Escribir métodos de serialización personalizados es la mejor manera que conozco (y realmente no es tan difícil). Usted tiene requisitos de serialización personalizados que se prestan a un serializador personalizado ... ¿Hay alguna razón particular por la que no desea ir por esa ruta? – Bill

+0

La razón principal es que estoy en un entorno de framework donde la serialización debe ser hecha por el framework y solo devuelvo los resultados como objetos. – mayu

+0

¿Puedes ver lo que otras clases dentro de este entorno están haciendo para resolver este problema, entonces? Si vas a hackearlo en pedazos, también puedes hackearlo de la misma forma que otras personas :) – Bill

Respuesta

5

Esto depende mucho del marco de serialización que esté utilizando. Usted menciona XML y JSON - así, la primera cosa a destacar es que sólo se puede decorar con:

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

o

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

cuales XmlSerializer y JavascriptSerializer responderá a. Si tiene que tomar la decisión sobre una base por ejemplo, hay los ShouldSerialize* y *Specified patrones:

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

Lo anterior es un modelo basado en nombre, que es utilizado por XmlSerializer y otros; tiene un doble:

[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 */ } 
} 

No necesita hacer nada para conectarlos, funcionan automáticamente.

Los diferentes serializadores permiten diferentes patrones.

Además, a veces puede agregar cosas como [XmlIgnore] en tiempo de ejecución, por ejemplo, a través de XmlAttributeOverrides, o el equivalente para cualquier serializador dado.

+0

Marqué esto como la respuesta ya que responde a la pregunta, pero describí mi enfoque elegido en la pregunta misma como == Enfoque elegido. – mayu

0

Puede decorar sus propiedades internas con un atributo personalizado que indique que deben incluirse (o ignorarse según sus requisitos) y luego en su ToSerialize comprobar el atributo.

[AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = true)] 
public class ShouldSerializeAttribute : Attribute { } 

Luego, su definición de clase resultante se vería así:

class Car 
{ 
    [ShouldSerialize] 
    public int PropX {get;set} 

    // This property won't be serialized because it is internal 
    public int PropY { get; set; } 
} 

Usted ToSerialize sería algo como:

object ToSerialize() 
{ 
    Car car = GetCar(); 

    foreach(PropertyInfo propInfo in car.GetType().GetProperties()) 
    { 
     if(ShouldSerialize(propInfo)) 
     { 
      return car; 
     } 
    } 
} 

Dónde ShouldSerialize podría parecerse a:

internal bool ShouldSerialize(PropertyInfo propInfo) 
{ 
    return propInfo.GetCustomAttributes(typeof(ShouldSerializeAttribute), true).FirstOrDefault() != null; 
} 

ACTUALIZACIÓN

@ Basado en una visión de Bill en los comentarios. Si usted está buscando sólo para serializar atributos públicos cuando level es Level.Public se puede lograr ese efecto mediante la reflexión sobre las propiedades del tipo utilizando el BindingFlags.DeclaredOnly bandera:

foreach(PropertyInfo propInfo in car.GetType().GetProperties(BindingFlags.DeclaredOnly)) 

Esto debería devolver una lista de las propiedades sólo declarada por la corriente instancia de car.

+1

No creo que esto responda la pregunta.Necesita serializar un conjunto diferente de propiedades según el nivel requerido, no solo serializar si es público. – Bill

+0

@Bill - ¿En qué parte de la pregunta dice eso (o lo dijo cuando respondí)? El código que OP publicó no lo lograría, entonces ¿qué le hace pensar que es lo que quiere? A menos que haya leído a medias la intención del código. –

+0

@M En su código, devuelve CarInternal (todas las propiedades se serializan) o CarPublic (solo las propiedades públicas se serializan). Vea su método ToSerialize que hace la elección basada en Level.Public. – Bill

Cuestiones relacionadas