2010-01-25 20 views
37

Tengo la situación extremadamente improbable y original de querer devolver una matriz de solo lectura de mi propiedad. Hasta ahora solo conozco una forma de hacerlo: a través del System.Collections.ObjectModel.ReadOnlyCollection<T>. Pero eso de alguna manera me parece incómodo, sin mencionar que esta clase pierde la capacidad de acceder a los elementos de la matriz por su índice (agregado: whoops, me olvidé del indexador). ¿No hay mejor manera? ¿Algo que podría hacer que el conjunto sea inmutable?¿Cuál es la mejor manera de crear una matriz de solo lectura en C#?

+2

ReadOnlyCollection tiene un indexador, admite la indexación. No puedes hacer una matriz inmutable. –

+1

En realidad, ReadOnlyCollection ** does ** tiene una propiedad del indexador ... – BFree

+0

@BFree - pero (importante) que no le permite reasignar éxito artículos a través de la @nobugz indexador –

Respuesta

34

Uso ReadOnlyCollection<T>. Es de solo lectura y, al contrario de lo que crees, tiene un indexador.

Las matrices no son inmutables y no hay forma de hacerlo sin usar una envoltura como ReadOnlyCollection<T>.

Tenga en cuenta que la creación de un contenedor ReadOnlyCollection<T> es una operación O (1) y no implica ningún costo de rendimiento.

actualización
Otras respuestas han sugerido sólo fundición colecciones a la nueva IReadOnlyList<T>, que se extiende IReadOnlyCollection<T> añadir un indexador. Desafortunadamente, esto en realidad no le da control sobre la mutabilidad de la colección, ya que podría ser devuelta al tipo de colección original y mutada.

En su lugar, usted debe utilizar el ReadOnlyCollection<T> (el List<T> método AsReadOnly() o Array s método estático AsReadOnly() ayuda para envolver las listas y matrices en consecuencia) para crear un acceso inmutable a la colección y luego exponer que, ya sea directamente o como cualquier una de las interfaces que admite, incluyendo IReadOnlyList<T>.

+3

'ReadOnlyCollection' no es utilizable como una colección inmutable. Es un poco _less_ que un Array, pero con el código _more_ a su alrededor. Su única 'característica' no es permitir que sus _usuarios_ modifiquen la colección, pero ni siquiera garantiza eso a los usuarios ... En pocas palabras: ¡inútil! – gatopeich

+4

@gatopeich: inútil es una afirmación infundada. Proporcione sus fuentes en cuanto a su falta de uso. Sin embargo, buen diantre. –

+1

Ojalá hubiera una interfaz IReadOnlyList que implementaría esta clase. – Kugel

1

IEnumerable viene a la mente.

+0

¿Quiere lanzar mi matriz a un IEnumerable y devolver eso? Eso sería incluso peor que ReadOnlyCollection. Antes que nada, cualquiera podría lanzarlo fácilmente al arreglo y modificarlo. En segundo lugar, proporciona un subconjunto aún más pequeño de la funcionalidad que ofrecen las matrices. –

+4

Puede hacer que esto funcione bien con un iterador (declaración de rendimiento). –

0

Es posible que desee implementar la interfaz IEnumerable y sobrecargar el este [int] operador para denegar el acceso a su setter

+1

decir que? ¿De qué manera es mejor que ReadOnlyCollection mencionado anteriormente? –

+1

traducción: "es posible que desee implementar una interfaz, pero no ponerlo en práctica" -1 –

5

Si realmente desea que se devuelva una matriz, pero tiene miedo de que el consumidor de la matriz se meta con los datos internos, simplemente devuelva una copia de la matriz. Personalmente sigo pensando ReadOnlyCollection<T> es el camino a seguir, pero si realmente desea una matriz .....

+3

Parece una buena idea, hasta que te des cuenta de qué clase.MyArray [i] hará en un bucle. Hazlo 1000 veces y tienes 1000 copias de la matriz. – RichardOD

+0

@RichardOD Cierto, pero tú no haces eso. Si accede por índice en la clase principal, simplemente devuelve los elementos. Si devuelve la matriz, proporcione al usuario una función que devuelva una copia de la matriz e itere sobre ella. –

9

.NET Framework 4.5 introdujo IReadOnlyList<T> que se extiende desde IReadOnlyCollection<T> sumando T this[int index] { /*..*/ get; }.

Puede transmitir de T[] a IReadOnlyList<T>. Una ventaja de esto es que (IReadOnlyList<T>)array comprensiblemente es igual a array; no hay boxeo involucrado.

Por supuesto, como una envoltura no se está utilizando, (T[])GetReadOnlyList() sería mutable.

+0

El problema con solo enviar contenido a la interfaz es que se puede enviar de nuevo, como usted señala. Esto significa que no tiene control sobre la mutabilidad de los datos. Debería seguir utilizando 'ReadOnlyCollection ' para envolver primero y luego usar 'IReadOnlyList ' para que tenga control sobre cómo se usan sus datos. –

+3

Argumentaría que esto se reduce a contratos: si le devuelvo un objeto, entonces le he dado permiso para usar los métodos expuestos por ese objeto. Si decide, por ejemplo, usar la reflexión para mirar y manipular las entrañas de ese objeto, entonces se perderán todas las garantías. Del mismo modo, si le devuelvo un IEnumerable , le he otorgado el derecho de enumerar los resultados. Si decide lanzar directamente el IEnumerable a una lista y borrarlo (léase: '(List ) result' over' result.ToList() '), entonces está trabajando con un comportamiento que no he definido. – Warty

+1

Tenga en cuenta que iterar a través de esto es casi diez veces más lento que iterar a través de una matriz. –

Cuestiones relacionadas