2012-08-24 11 views
5

Ho 2 tipi: BaseQuestion e Question. Question eredita alcune proprietà da BaseQuestion. Ora ho creato un'API Web per rendere disponibile un BaseQuestion. Il tipo di dati Question ha proprietà aggiuntive che non desidero rendere disponibili. Ho un metodo che recupera uno Question e il mio piano iniziale era semplicemente implicitamente lo upcast a BaseQuestion. Ho pensato che avrebbe perso tutte le proprietà extra che non voglio rendere accessibile e potrei restituirlo. Beh, non è così. Questo è quello che faccio:C#: la superclasse ha ancora informazioni sottoclasse dopo l'aggiornamento

Question q = allQuestions[0]; 
BaseQuestion bq = q; 
string type = bq.GetType().ToString(); 

Il tipo di bq è ancora "Domanda". Non riesco ad accedere alle proprietà di BaseQuestion, ma posso ancora vederle nel debugger e sono nell'output JSON che invio al client.

Qualche idea su come "forzare" bq per essere di tipo BaseQuestion e per non avere proprietà definite nella sottoclasse?

+0

Il tipo di bq variabile è BaseQuestion. Il tipo di runtime dell'oggetto a cui si riferisce bq è Question. Non sei sicuro di cosa intendi con "forza bq per essere di tipo BaseQuestion".Sarai in grado di accedere ai membri di BaseQuestion solo tramite la variabile bq. – lesscode

+1

Penso che la tua confusione non stia comprendendo che ciò che hai dato sono ** riferimenti ** agli oggetti in memoria. –

+0

Simon, buon punto. Quindi fammi riformulare: Come posso creare un nuovo oggetto di tipo Domanda e copiare automaticamente tutti i valori delle proprietà? Automaticamente intendo che io ** non ** voglio implementarlo. IMHO questo scenario non è affatto unico per la mia situazione e dovrebbe essere coperto da .NET. – Jan

risposta

11

La tipizzazione non modifica la natura dell'oggetto, ma modifica solo la vista dell'oggetto. Quando si esegue il typecast sul tipo di base, si guarda l'oggetto attraverso un filtro che può vedere solo i membri definiti sul tipo di base, indipendentemente da qualcos'altro definito nell'oggetto reale.

Quando si restituisce un oggetto da una chiamata di servizio Web, è l'oggetto effettivo che verrà serializzato e inviato di nuovo attraverso il filo - tutti i suoi membri serializzabili.

Una tecnica che è possibile utilizzare per impedire che i membri della classe di domande derivata vengano restituiti al chiamante dell'API consiste nell'eliminare la serializzazione dei membri dichiarati nella classe di domande. Esistono diversi sottosistemi di serializzazione in .NET, ma se utilizzi XmlSerialization devi decorare i membri dichiarati nella classe Question con gli attributi [XmlIgnore] per impedire che vengano serializzati da XmlSerialization. Se utilizzi un sottosistema di serializzazione diverso, dovrai individuare l'analogo di questo in quel sistema.

Un'altra possibilità è definire i contratti di interfaccia per i servizi API Web. Le vostre classi BaseQuestion e Domanda implementerebbero una o più di queste interfacce di contratto. Credo che ciò limiterà la serializzazione solo alle proprietà definite nell'interfaccia del contratto, indipendentemente da quale sia l'oggetto reale.

Se tutto il resto fallisce, la soluzione di forza bruta è costruire un'istanza di BaseQuestion in una variabile temporanea, copiare le proprietà rilevanti dall'oggetto Domanda effettivo all'oggetto tempor e restituire l'oggetto temp. Questo è rude e rozzo e deve esserci un modo migliore, ma funzionerà.

+0

Non riesco a modificare i tipi Question/BaseQuestion in quanto l'API Web non è il loro unico utente. Sono totalmente d'accordo sul fatto che "ci dev'essere un modo migliore", e ho cercato dappertutto, ma sono uscito vuoto. Penso che la mia frustrazione sia abbastanza grande da creare un convertitore esplicito. Ma grazie per l'aiuto! – Jan

+0

La maggior parte di questa risposta è corretta, ad eccezione della parte relativa alla limitazione della serializzazione basata sull'ereditarietà dell'interfaccia. Quella parte non funziona perché non cambia l'oggetto originale. Mi piacerebbe che funzionasse così :( –

+0

Invece di creare una "interfaccia di contratto", crea un "modello di contratto" di qualunque cosa tu desideri serializzare e deserializzare, scrivi funzioni di conversione o usa una libreria come [AutoMapper] (https: // github.com/AutoMapper/AutoMapper) per convertire il modello "completo" nella versione ridotta che contiene solo le proprietà che si desidera serializzare. – MarioDS

1

Il controllo di tipo modifica solo il tipo di riferimento all'oggetto, non l'oggetto stesso.

Calling .GetType() su un'istanza di Question restituirà sempre il tipo Question a prescindere dal tipo di variabile che fa riferimento a esso.

Se si desidera il tipo di base, è necessario chiamare la proprietà .BaseType sul tipo.

Quindi, qualcosa di simile:

string type = q.GetType().BaseType.ToString(); 
+0

Quello era solo per mostrare cosa intendo. Devo avere un oggetto che _solo_ contiene le proprietà della classe base – Jan

+0

Non è quello che ti fornirà il tipo di casting per 'BaseQuestion'? – Enigmativity

+0

Questo è quello che pensavo, ma a quanto pare non lo è. Non cambio l'oggetto stesso, cambio solo il contenitore che immagazzino il riferimento in. Le proprietà della sottoclasse sono ancora presenti e verranno serializzate. – Jan