2012-02-14 16 views
8

Supponiamo di devo serializzare un oggetto di una classe auto a livelli esempio Interno e Pubblico. Alcune delle proprietà nel livello Pubblico non dovrebbero essere serializzate in quanto interne.Decidere quali proprietà vengono serializzati in fase di esecuzione

In questo momento il modo 'semplice' mi viene in mente per raggiungere questo obiettivo è quello di utilizzare l'ereditarietà:

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

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

Poi ho potuto

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

Il risultato della ToSerialize() è preso da un framework (non ho il controllo ) e serializzato su JSON o XML.

ho omesso gli attributi di serializzazione XML per semplicità.

Questo si sente come un hack hack e si prende solo finora. C'è modo migliore (modi?) Per raggiungere questo obiettivo?

penso che la sua ormai chiaro, ma vorrei evitare di scrivere i miei metodi di serializzazione per JSON e XML.

Grazie in anticipo Tymek

EDIT ==

Per chiarire, io voglio essere in grado di serializzare più livelli:

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

e

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

== Approccio scelto

ho segnato la risposta di Marc Gravell come la risposta, in quanto fornisce le informazioni generiche di come C# ed è componenti 'standard' sostenere quello che ho chiesto.

Tuttavia penso che l'approccio migliore per il mio problema è quello di utilizzare le classi proxy come indicato sopra e avere la classe di essere serializzato in questo schema multi-livello con metodi come indicato qui sotto.

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

questo permette di mantenere i Car0..3 classi molto semplice, con solo proprietà, per mantenere e comprendere.

+1

Scrivere i metodi di serializzazione personalizzati è il modo migliore che conosco (e in realtà non è così difficile). Hai requisiti di serializzazione personalizzati che si prestano ad un serializzatore personalizzato ... C'è un motivo particolare per cui non vuoi seguire questo percorso? – Bill

+0

Il motivo principale è che sono in un ambiente framework in cui la serializzazione deve essere eseguita dal framework e restituisco solo i risultati come oggetti. – mayu

+0

Puoi vedere quali altre classi all'interno di questo ambiente stanno facendo per risolvere questo problema? Se hai intenzione di hackerarlo a pezzi, potrebbe anche modificarlo allo stesso modo degli altri :) – Bill

risposta

5

Dipende molto da quale framework di serializzazione si sta utilizzando. Lei parla di XML e JSON - bene, la prima cosa da notare è che si può solo decorare con:

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

o

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

che XmlSerializer e JavascriptSerializer dovrà rispondere. Se avete bisogno di prendere la decisione su una base per-esempio, v'è la ShouldSerialize* e *Specified modelli:

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

è un nome a base di modello, che viene utilizzato da XmlSerializer e altri; ha una doppia:

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

Non è necessario fare nulla per legare in su - funzionano automaticamente.

I diversi serializzatori consentono diversi schemi.

Inoltre, a volte è possibile aggiungere cose come [XmlIgnore] in fase di esecuzione, ad esempio tramite XmlAttributeOverrides o l'equivalente per qualsiasi serializzatore specificato.

+0

Ho contrassegnato questa risposta come risposta alla domanda, ma ho descritto il mio approccio scelto nella domanda stessa come == Approccio scelto. – mayu

0

È possibile decorare le proprietà interne con un attributo personalizzato che indica che devono essere incluse (o ignorate a seconda delle esigenze) e quindi nel proprio ToSerialize controllare l'attributo.

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

Allora la vostra definizione di classe risultante sarà simile:

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

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

È ToSerialize sarebbe simile:

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

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

Dove ShouldSerialize potrebbe apparire come:

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

UPDATE

Basato su @ intuizione di Bill nei commenti. Se stai cercando di serializzare solo attributi pubblici quando level è Level.Public è possibile ottenere questo effetto riflettendo sulle proprietà del tipo utilizzando la bandiera BindingFlags.DeclaredOnly:

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

Questo dovrebbe restituire un elenco delle proprietà dichiarati solo dalla corrente istanza di car.

+1

Non penso che questo risponda alla domanda.Ha bisogno di serializzare un diverso insieme di proprietà in base al livello richiesto, non solo serializzare se pubblico. – Bill

+0

@ Bill - Dove nella domanda si dice (o ha detto che quando ho risposto)? Il codice pubblicato dall'OP non raggiungerebbe questo, quindi cosa ti fa pensare che sia quello che vogliono? A meno che non abbia midread l'intenzione del codice. –

+0

@M Nel suo codice, restituisce CarInternal (tutte le proprietà vengono serializzate) o CarPublic (solo le proprietà pubbliche vengono serializzate). Vedi il suo metodo ToSerialize che rende la scelta basata su Level.Public. – Bill

Problemi correlati