2009-06-02 19 views
33

Giuro di aver visto un esempio di questo, ma ho cercato su Google un po 'e non riesco a trovarlo.C# restituisce una variabile come sola lettura da get; impostato;

Ho una classe che ha un riferimento a un oggetto e deve avere un GET; metodo per questo. Il mio problema è che non voglio che qualcuno sia in grado di giocherellare con esso, cioè voglio che ottengano una versione di sola lettura di esso, (nota che ho bisogno di essere in grado di alterarlo all'interno della mia classe).

Grazie

+1

Sono sorpreso da quante persone hanno frainteso la domanda. Jon Skeet e Anton Gogolev hanno ragione. –

+1

Non pensavo di aver frainteso, ma ho comunque votato - oh bene – ChrisF

+0

era una domanda trabocchetto :) –

risposta

51

No, non c'è modo di fare questo. Ad esempio, se si restituisce un List<string> (e non è immutabile), i chiamanti saranno in grado di aggiungere voci alle voci.

Il modo normale per restituire un involucro immutabile, ad es. ReadOnlyCollection<T>.

Per altri tipi modificabili, potrebbe essere necessario clonare il valore prima di restituirlo.

Si noti che la semplice restituzione di una vista di interfaccia immutabile (ad esempio la restituzione di IEnumerable<T> anziché List<T>) non interromperà il richiamo del chiamante al tipo mutabile e alla mutazione.

EDIT: Si noti che, a parte ogni altra cosa, questo tipo di preoccupazione è una delle ragioni per le quali tipi immutabili rendono più facile ragionare sul codice :)

+2

+1 per la clonazione (tranne che ho già fatto +1) –

+2

Per prima cosa dici che non può essere fatto e quindi punti alla soluzione di clonazione. Inoltre, forse la clonazione è una nuova idea per C#, ma è stata lì per molto tempo in C++, per esempio. Inoltre, non è strettamente clonazione - sta creando una copia dei dati interni e restituendo questa copia, non i dati originali - la copia non deve essere dello stesso tipo dell'originale. – mayu

6

restituire un riferimento a un'interfaccia stripped-down:

interface IFoo 
    string Bar { get; } 

class ClassWithGet 
    public IFoo GetFoo(...); 
+1

Idealmente includendo un'implementazione 'private' o' internal' di IFoo in modo che non possa essere restituito;) – jerryjvl

+0

Hum no, se l'Interfaccia è interna o Privata non lo farai essere in grado di restituire un membro pubblico che ha un tipo non accessibile. Questo non verrà compilato: "Accessibilità incoerente: il tipo di campo ... è meno accessibile del campo ..." –

3

Questo non è possibile. Ottieni e imposta gli accessor ai tipi di riferimento ottieni e imposta il riferimento all'oggetto. È possibile impedire le modifiche al riferimento utilizzando un setter privato (o interno), ma non è possibile impedire le modifiche all'oggetto stesso se è esposto da un getter.

+0

Sì, è possibile. È possibile restituire una copia dei dati. – mayu

3

Se l'oggetto non è troppo complicato/esteso, scrivere attorno a esso un involucro.

ad esempio:

class A { 
    public string strField = 'string'; 
    public int intField = 10; 
} 

class AWrapper { 
    private A _aObj; 

    public AWrapper(A aobj) { 
     _aObj = A; 
    } 

    public string strField { 
     get { 
      return _aObj.strField; 
     } 
    } 

    public int intField { 
     get { 
      return _aObj.intField; 
     } 
    } 
} 

Così ora tutto ciò che fai è dare il vostro codice client un'istanza della classe AWrapper in modo che essi possono utilizzare solo ciò che si consente loro di vedere.

questo potrebbe risultare un po 'complicato e potrebbe non essere scalabile correttamente se la tua classe base non è impostata su pietra, ma per la maggior parte delle situazioni semplici potrebbe semplicemente fare il trucco. Credo che questo si chiama un modello di facciata (ma non citare me su quel =))

0

sono d'accordo con ReadOnlyCollection

Vedere il mio codice semplice:

private List<Device> _devices; 
public readonly System.Collections.ObjectModel.ReadOnlyCollection<Device> Devices 
{ 
get 
{ 
return (_devices.AsReadOnly()); 
} 

}

ReadOnlyCollection non ha aggiunto il metodo in modo che l'utente non possa aggiungere delle proprietà. Ma non c'è alcuna garanzia che l'utente possa modificare gli oggetti chiamando i loro metodi ....

1

La tua domanda si legge come siete alla ricerca di:

public PropertyName { get; private set; } 

Ma poi, dato le risposte finora non sono sicuro di interpretare correttamente la tua domanda. Inoltre, chi sono io per interrogare Jon Skeet? :)

+0

Che restituisce un riferimento che è di sola lettura, poiché non può essere assegnato, ma è comunque possibile modificare l'oggetto perché le sue proprietà non sono di sola lettura – DCShannon

0

Ho affrontato questo problema in un certo modo. Ho una classe CategoryViewModel, che hanno una categoria di proprietà che voglio privato di sola lettura:

public CategoryViewModel 
{ 
    private Category { get; } 

} 

In realtà, io voglio che sia esportato in sola lettura per altra classe. Tuttavia non posso fare una cosa simile. Nel mio caso (forse aiuterà alcuni altri ragazzi), voglio aggiungerlo a un repository. L'unico modo che ho trovato è quello di avere una funzione con il repository come param 1, ed un'azione come param 2:

public void ApplyAction(ICategoryRepository repo, Action<ICategoryRepository, Category> action) 
{ 
    action(repo, Category); 
} 

Come quella, da qualche altra parte, non posso fare una cosa:

categoryViewModel.ApplyAction(_repository, (r, c) => r.MarkForInsertOrUpdate(c)); 

Questo può aiutare altri a esporre la proprietà solo per determinati casi e in grado di gestirli.

Problemi correlati