2010-08-31 11 views
5

Recientemente comencé a usar F # para "trabajo real" y redescubrí la belleza de estructuras de datos inmutables como las uniones discriminadas y los registros en F #. También descubrí que son bastante sencillos de usar desde C#, especialmente porque no requieren ninguna dependencia directa del tiempo de ejecución F #. Sin embargo, cuando se trata de representar listas en estas estructuras, aún no he encontrado una solución ideal.¿Cuál es la mejor manera de representar una lista inmutable en .NET?

Mi primer intento fue para escribir las listas como SEQ < 'a> (IEnumerable en el C# mundo) que proporciona una interfaz agradable colección general sin exportar ningún método para la mutación de la colección de la manera ICollection <> y sus amigos lo hace. Sin embargo, dado que no tengo control sobre el constructor de una unión o registro discriminado, es posible que el creador de una instancia de estos tipos proporcione una implementación IEnumerable <> que podría cambiar o arrojarse cuando se use (como una expresión LINQ) . IEnumerable <> no me proporcionará ninguna ayuda del compilador para probar que el valor es inmutable y, por lo tanto, es seguro para la ejecución de subprocesos.

Mi estrategia actual es usar el tipo de lista F # que garantiza una colección inmutable, pero agrega una dependencia en el tiempo de ejecución F # y se ve un poco apagado cuando se usa desde proyectos que no son F #. Sin embargo, permite la coincidencia de patrón F # que IEnumerable <> no. Tampoco da ninguna opción en la representación real de una lista, y en algunos casos (como grandes listas de valores primitivos) la representación de la lista F # no encaja realmente.

Lo que realmente me gustaría ver es un tipo de matriz inmutable en .NET, representada de forma tan compacta como la matriz normal, pero con la garantía del compilador de no estar mutado. Me encantaría const como en C++, aunque probablemente no sea muy probable que suceda. Mientras tanto, ¿hay alguna otra opción que me haya perdido?

+0

Ni siquiera las listas F # son realmente indudablemente inmutables, puedes mutarlas en su lugar mediante el uso de la reflexión (ver http://en.wikibooks.org/wiki/F_Sharp_Programming/Reflection);) – Juliet

+1

ver también http: // stackoverflow .com/questions/3485262/efficient-inmutable-extensible-collections-for-net –

+2

Me encantaría un tipo de matriz inmutable eficiente en tiempo y espacio también; estamos * considerando * hacer el lenguaje y el trabajo en tiempo de ejecución para que suceda en una * futura versión hipotética * de C#, pero desafortunadamente probablemente no termine en el medio de la lista de prioridades. (Recuerde, todas las reflexiones de Eric sobre las características ficticias sin presupuestos implementados en productos no anunciados son solo para fines de entretenimiento). –

Respuesta

7

Si lo que desea es una implementación gama inmutable a continuación, puedes usar algo como lo siguiente

public sealed class ImmutableArray<T> : IEnumerable<T>{ 
    private readonly T[] m_array; 
    public T this[int index] { 
    get { return m_array[index]; } 
    } 
    public int Length { 
    get { return m_array.Length; } 
    } 
    public ImmutableArray(IEnumerable<T> enumerable) { 
    m_array = enumerable.ToArray(); 
    } 
    // IEnumerable<T> implementation ommitted 
} 
+0

Esa podría ser, de hecho, la mejor manera. El constructor tendría que copiar la matriz, pero al menos podría pasar libremente una instancia de este tipo y saber que no cambiaría su contenido. – SoftMemes

2

Envuelva su gama normal en una instancia ReadOnlyCollection<T>:

var readOnlyData = new ReadOnlyCollection<TheType>(theRealCollection); 

(Nota: esto hace no copiar la colección subyacente, pero contiene una referencia y se implementan miembros modificadores de IList<T> etc. para lanzar una excepción.)

+0

Tendría que escribir estáticamente las propiedades como ReadOnlyCollection <>, que es posible, pero en realidad no ofrece ninguna ventaja sobre tipearlo como IEnumerable <>, ya que el creador aún podría proporcionar un ReadOnlyCollection respaldado por una colección no mutable. ReadOnlyCollection <> también implementa una serie de interfaces que una colección inmutable no debería admitir. – SoftMemes

+0

El problema con 'ReadOnlyCollection ' es que no es inmutable, es solo de solo lectura. – JaredPar

1

Recomiendo mirar la serie Eric Lippert's en immutability, es una lectura muy útil. La Parte 4 sobre un immutable queue sería un buen lugar para comenzar.

+0

El problema es que mi implementación de una cola inmutable no es tan eficiente desde el punto de vista del espacio como una matriz. Una matriz de, por ejemplo, bytes, ocupa un byte por elemento. Una cola de bytes ocupa docenas de bytes por elemento. –

+0

Buen punto, no pensé en eso, gracias por la información. –

+0

Aunque el blog de Erics es definitivamente interesante, lo que realmente estaba buscando era una estructura de datos existente para usar para representar listas inmutables, no cómo implementar una lista inmutable o cualquiera de las estructuras de datos inmutables más desafiantes. – SoftMemes

Cuestiones relacionadas