Ho la situazione estremamente improbabile e originale di voler restituire un array di sola lettura dalla mia proprietà. Finora sono a conoscenza di un solo modo di farlo - attraverso lo System.Collections.ObjectModel.ReadOnlyCollection<T>
. Ma che sembra in qualche modo imbarazzante per me, Senza contare che questa classe perde la capacità di accedere agli elementi dell'array dal loro indice (aggiunto: whoops, ho perso l'indicizzatore). Non c'è modo migliore? Qualcosa che potrebbe rendere immutabile la matrice stessa?Qual è il modo migliore per creare un array di sola lettura in C#?
risposta
Usa ReadOnlyCollection<T>
. È di sola lettura e, contrariamente a quello che credi, ha un indicizzatore.
Gli array non sono immutabili e non è possibile eseguirli senza utilizzare un wrapper come ReadOnlyCollection<T>
.
nota che la creazione di un involucro ReadOnlyCollection<T>
è un O (1) il funzionamento, e non comporta alcun costo prestazioni.
Aggiornamento
altre risposte hanno suggerito appena colata collezioni al più recente IReadOnlyList<T>
, che si estende IReadOnlyCollection<T>
aggiungere un indicizzatore. Sfortunatamente, questo in realtà non ti dà il controllo sulla mutabilità della collezione poiché potrebbe essere ricondotta al tipo di raccolta originale e mutata.
Invece, si dovrebbe comunque utilizzare il ReadOnlyCollection<T>
(il List<T>
metodo di AsReadOnly()
, o Array
s metodo statico AsReadOnly()
aiuta a avvolgere le liste e array di conseguenza) per creare un accesso immutabile alla raccolta e poi esporre che, direttamente o come qualsiasi una delle interfacce che supporta, tra cui IReadOnlyList<T>
.
'ReadOnlyCollection' non è utilizzabile come collezione immutabile. È un po 'senza _ di una matrice, ma con il codice _more_ attorno ad essa. È solo 'caratteristica' che non consente ai suoi utenti di modificare la raccolta, ma non garantisce nemmeno agli utenti ... In conclusione: inutile! – gatopeich
@gatopeich: Inutile è un'affermazione infondata. Si prega di fornire le vostre fonti per la sua mancanza di uso. Bel rant, però. –
Vorrei che ci fosse un'interfaccia IReadOnlyList che questa classe avrebbe implementato. – Kugel
IEnumerable viene in mente.
Intendi lanciare il mio array su un oggetto IEnumerable e restituirlo? Sarebbe quindi ancora peggio di ReadOnlyCollection. Prima di tutto, chiunque potrebbe facilmente tornare all'array e modificarlo. In secondo luogo fornisce un sottoinsieme ancora più piccolo della funzionalità offerta dagli array. –
È possibile eseguire questa operazione correttamente con un iteratore (dichiarazione di resa). –
Si potrebbe desiderare di implementare l'interfaccia IEnumerable e sovraccaricare l'operatore this [int] di negare l'accesso al suo setter
Dite cosa? In che modo è meglio di ReadOnlyCollection menzionato sopra? –
traduzione: "potresti voler implementare un'interfaccia ma non implementarla" -1 –
Se si vuole veramente una matrice restituita, ma hanno paura che il consumatore del pasticcio array con i dati interni, solo restituire una copia della matrice. Personalmente penso ancora ReadOnlyCollection<T>
è la strada da percorrere, ma se si VERAMENTE desidera una serie .....
Sembra una buona idea, finché non ti rendi conto di cosa class.MyArray [i] farà in un ciclo. Fallo 1000 volte e hai 1000 copie dell'array! – RichardOD
@RichardOD Vero, ma non lo fai. Se stai accedendo per indice sulla classe principale, restituisci gli elementi. Se si restituisce la matrice, fornire all'utente una funzione che restituirà una copia dell'array e eseguirà un'iterazione. –
Da .NET Framework 2.0 e lì è Array.AsReadOnly che crea automaticamente un wrapper ReadOnlyCollection per voi.
.NET Framework 4.5 ha introdotto IReadOnlyList<T>
che si estende da IReadOnlyCollection<T>
aggiungendo T this[int index] { /*..*/ get; }
.
È possibile trasmettere da T[]
a IReadOnlyList<T>
. Un vantaggio di questo è che (IReadOnlyList<T>)array
è comprensibilmente uguale a array
; non è coinvolta la boxe.
Naturalmente, non viene utilizzato un involucro, (T[])GetReadOnlyList()
sarebbe mutevole.
Il problema con il semplice collegamento all'interfaccia è che può essere ricollocato di nuovo, come si fa notare. Ciò significa che non hai controllo sulla mutabilità dei dati. Dovresti comunque usare 'ReadOnlyCollection
Direi che questo si riduce ai contratti: se ti restituisco un oggetto, ti ho dato il permesso di usare qualsiasi metodo esposto da quell'oggetto. Se si decide, ad esempio, di utilizzare la riflessione per sbirciare e manipolare le interiora di quell'oggetto, tutte le garanzie vengono perse. Allo stesso modo, se ti restituisco un oggetto IEnumerable
Si noti che l'iterazione di questo è quasi dieci volte più lento di iterare attraverso un array. Aggiornamento –
ReadOnlyCollection ha un indicizzatore, supporta l'indicizzazione. Non puoi rendere un array immutabile. –
In realtà, ReadOnlyCollection ** fa ** ha una proprietà indicizzatore ... –
BFree
@BFree - ma (importante) non ti consentirà di riassegnare correttamente gli articoli tramite l'indicizzatore –