2009-03-06 13 views
19

Ho la seguente classe:"Sola lettura" Proprietà Accessor in C#

class SampleClass 
{ 
    private ArrayList mMyList; 

    SampleClass() 
    { 
     // Initialize mMyList 
    } 

    public ArrayList MyList 
    { 
     get { return mMyList;} 
    } 
} 

voglio che gli utenti siano in grado di ottenere mMyList che è il motivo per cui ho esposto il "get" tramite una proprietà però non lo faccio vuoi che le modifiche apportate all'oggetto (ad es. MyList.Add (new Class());) tornino nella mia classe.

Immagino di poter restituire una copia dell'oggetto ma che potrebbe essere lento e sto cercando un modo che fornisca un errore in fase di compilazione che informa l'utente che non dovrebbero aspettarsi di poter modificare il valore restituito dalla proprietà.

È possibile?

+0

questione connessa: http://stackoverflow.com/questions/681287/how-to-make-a-reference-type-property-readonly –

+2

Does 'Lista : ReadOnlyCollection ' in .NET 4.5 modificare una di queste? http://www.infoq.com/news/2011/10/ReadOnly-WInRT/ –

risposta

25

Con ArrayList si è abbastanza limitati perché non esiste una classe di raccolta non generica di sola lettura nel BCL. La soluzione rapida e sporca consiste nel restituire un tipo di IEnumerable.

public IEnumerable MyList 
    { 
     get { return mMyList;} 
    } 

Questo non sarà effettivamente impedire a qualcuno di fusione a ArrayList, ma non consentirà modifiche per impostazione predefinita sia

È possibile restituire un elenco di sola lettura in modo efficace chiamando ArrayList.ReadOnly. Comunque il suo tipo di ritorno è un ArrayList, quindi l'utente sarebbe comunque in grado di compilare .Add, ma produrrebbe un errore di runtime.

1

È necessario includere il valore restituito in una raccolta di sola lettura.

19

Utilizzare il metodo ArrayList.ReadOnly() per creare e restituire un wrapper di sola lettura attorno all'elenco. non copierà la lista, ma semplicemente farà un wrapper di sola lettura attorno ad esso. Per ottenere il controllo in fase di compilazione, probabilmente si desidera restituire il wrapper di sola lettura come IEnumerable come suggerisce @Jared.

public IEnumerable MyList 
{ 
    get { return ArrayList.ReadOnly(mMyList); } 
} 

Una collezione che si è in sola lettura semplicemente un insieme con un involucro che impedisce la modifica della collezione . Se vengono apportate modifiche alla raccolta sottostante , la raccolta di sola lettura riflette tali modifiche.

Questo metodo è un'operazione O (1).

Reference

+2

Sono contrario a questa soluzione perché trasforma quello che dovrebbe essere un errore in fase di compilazione in un errore di runtime. – JaredPar

+0

-1, OP: "Sto cercando un modo che fornisca un errore ** in fase di compilazione **" –

+0

Senza copiare su ReadOnlyCollection - che ha anche detto che voleva evitare - Scelgo di imporre la lettura solo fingendo di essere di sola lettura. Fare entrambi è probabilmente meglio. – tvanfosson

-3

Basta fare la proprietà come Sealed (o NotInheritable in VB.NET) e di sola lettura, in questo modo:

public sealed readonly ArrayList MyList 
    { 
     get { return mMyList;} 
    } 

Inoltre non dimenticate di rendere il campo supporto in sola lettura :

private readonly ArrayList mMyList; 

Ma al fine di inizializzare il valore di mMyList, è necessario inizializzare solo nel costruttore, un s in questo esempio:

public SampleClass() 
{ 
    // Initialize mMyList 
    mMyList = new ArrayList(); 
} 
10

Solo per espandere la risposta di JaredPar. Come ha detto, restituire l'attuale campo di supporto non è completamente sicuro, poiché l'utente è ancora in grado di trasmettere dinamicamente lo IEnumerable a ArrayList.

vorrei scrivere qualcosa di simile per essere sicuri che nessuna modifica alla lista originale sono:

public IEnumerable MyList 
{ 
    get 
    { 
     foreach (object o in mMyList) 
      yield return o; 
    } 
} 

Poi di nuovo, vorrei probabily anche utilizzare un elenco generico (IEnumerable<T>) essere completamente SICURO tipo.

+0

* Questo * è quello giusto - vorrei poter votare due volte. Qualche problema con non chiamare 'yield break;' dopo il ciclo? – Jay

+0

@Jay: Non c'è bisogno di una esplicita interruzione del rendimento, al termine del ciclo. La fine del metodo implica la fine di 'Enumerator' (e' MoveNext' restituirà correttamente 'false'). –

+0

Con questa soluzione, l'utente non perde la funzionalità di ArrayList come l'accesso casuale veloce e il conteggio veloce? –

4

Utilizzare un ReadOnlyCollection.

return new ReadOnlyCollection<object>(mMyList).

Puoi anche creare il campo ReadOnlyCollection e rifletterà automaticamente le modifiche nell'elenco sottostante. Questa è la soluzione più efficiente.

Se si sa che mMyList contiene un solo tipo di oggetto (ad esempio, non ha nulla, ma DateTimes), è possibile restituire una (o qualche altro tipo) ReadOnlyCollection<DateTime> per la sicurezza ulteriore tipo. Se stai usando C# 3, si può semplicemente scrivere

return new ReadOnlyCollection<DateTime>(mMyList.OfType<DateTime>().ToArray())

Tuttavia, questo non aggiornerà automaticamente con la lista sottostante, ed è anche meno efficiente (Sarà copiare l'intera lista) . L'opzione migliore è quello di fare un generico mMyList List<T> (ad esempio, un List<DateTime>)

0

Disponibile da v2.0 .NET

public ArrayList MyList { get; private set; } 
+0

Sarai ancora in grado di utilizzare Aggiungi su un elenco esistente. –

Problemi correlati