2011-01-12 10 views
60

Trato de hacer algo como esto:línea de instancias de una lista constante

public const List<String> METRICS = new List<String>() 
     { 
      SourceFile.LOC, 
      SourceFile.MCCABE, 
      SourceFile.NOM, 
      SourceFile.NOA, 
      SourceFile.FANOUT, 
      SourceFile.FANIN, 
      SourceFile.NOPAR, 
      SourceFile.NDC, 
      SourceFile.CALLS 
     }; 

Pero, por desgracia esto no funciona:

FileStorer.METRICS' is of type 'System.Collections.Generic.List<string>'. A const field of a reference type other than string can only be initialized with null. 

¿Cómo puedo solucionar este problema?

+2

http://stackoverflow.com/questions/1109805/declaring-a-const-double-in-c –

+3

NOTA: Cerrar esta pregunta como un duplicado fue un error. La pregunta vinculada es acerca de ** matrices constantes **, esta pregunta trata sobre ** listas constantes **. Aunque ambos enfoques proporcionan más o menos la misma funcionalidad, son diferentes y las respuestas son diferentes. Solo las respuestas a esta pregunta mencionan 'ReadOnlyCollection'. Las preguntas están relacionadas, pero ninguna es duplicada de otra. – Athari

Respuesta

135

const es para las constantes de tiempo de compilación. Usted podría simplemente haga que sea static readonly, pero eso solo se aplicaría a la variable METRICS en sí misma (que normalmente debería ser Metrics en su lugar, por .NET naming conventions). No tendría la lista inmutable - por lo que alguien podría llamar METRICS.Add("shouldn't be here");

es posible que desee utilizar un ReadOnlyCollection<T> para envolverlo. Por ejemplo:

public static readonly IList<String> Metrics = new ReadOnlyCollection<string> 
    (new List<String> { 
     SourceFile.LoC, SourceFile.McCabe, SourceFile.NoM, 
     SourceFile.NoA, SourceFile.FanOut, SourceFile.FanIn, 
     SourceFile.Par, SourceFile.Ndc, SourceFile.Calls }); 

ReadOnlyCollection<T> simplemente envuelve una colección potencialmente mutable, pero como nada más tendrá acceso a la List<T> después, se puede considerar la colección general como inmutables.

(La capitalización aquí es sobre todo conjeturas -. El uso de nombres más completas las haga más claras, OMI)

Si se declara como IList<string>, IEnumerable<string>, ReadOnlyCollection<string> o alguna otra cosa depende de usted ... si esperas que solo debería tratarse como una secuencia, entonces IEnumerable<string> sería probablemente el más apropiado. Si el pedido es importante y desea que las personas puedan acceder a él por índice, puede ser apropiado IList<T>. Si desea que la inmutabilidad sea evidente, declararla como ReadOnlyCollection<T> podría ser útil, pero inflexible.

+16

encanta leer sus respuestas. – Pabuc

+1

vine aquí en busca de la 'nueva parte de la lista {...}'. Gracias Jon :) – Jason

+1

Supongo que hay una razón, pero para mí es extraño que 'ReadOnlyCollection' implemente' IList <> 'como expone' .Add' – AaronLS

19

En su lugar, necesitará usar una lista staticreadonly. Y si desea que la lista sea inmutable, puede considerar usar ReadOnlyCollection<T> en lugar de List<T>.

private static readonly ReadOnlyCollection<string> _metrics = 
    new ReadOnlyCollection<string>(new[] 
     { 
      SourceFile.LOC, 
      SourceFile.MCCABE, 
      SourceFile.NOM, 
      SourceFile.NOA, 
      SourceFile.FANOUT, 
      SourceFile.FANIN, 
      SourceFile.NOPAR, 
      SourceFile.NDC, 
      SourceFile.CALLS 
     }); 

public static ReadOnlyCollection<string> Metrics 
{ 
    get { return _metrics; } 
} 
0

.NET admite colecciones verdaderamente inmutables, vistas de solo lectura de colecciones mutables e interfaces de solo lectura implementadas por la colección mutable s.

Un tal colección es inmutable ImmutableArray <> el que puede crear como a.ToImmutableArray() en su ejemplo. Asegúrese de echarle un vistazo a las otras opciones de listas de MSDN porque es posible que reciba una colección inmutable diferente. Si desea hacer copias de la secuencia original con ligeras modificaciones, ImmutableList <> puede ser más rápido, por ejemplo (aunque la matriz es más económica de crear y acceder). Tenga en cuenta que a.Add (...); es válido, pero devuelve una nueva colección en lugar de cambiar a. Si tiene Resharper, eso le avisará si ignora el valor de retorno de un método puro como Agregar (y puede haber una extensión de roslyn para hacer algo similar que desconozco). Si va por esta ruta, considere omitir la Lista <> íntegramente y vaya directamente a colecciones inmutables.

Las vistas de solo lectura de las colecciones mutables son un poco menos seguras pero se admiten en las versiones anteriores de .NET. El tipo de ajuste se llama ReadOnlyCollection <>, que en su ejemplo puede construir como a.AsReadOnly(). Esta colección no garantiza la inmutabilidad; solo garantiza que no puedes cambiarlo.Algún otro código que comparte una referencia a la Lista subyacente <> aún puede cambiarlo. Además, ReadOnlyCollection también impone una sobrecarga adicional; por lo tanto, es posible que no ganes mucho al evitar las colecciones inmutables por motivos de rendimiento (TODO: comparar este reclamo). Puede utilizar un contenedor de solo lectura como este incluso en una API pública de forma segura; no hay forma (no reflexiva) de obtener la lista subyacente. Sin embargo, dado que a menudo no es más rápido que las colecciones inmutables, y tampoco es completamente seguro, recomiendo evitar ReadOnlyCollection <> - Nunca más uso esto personalmente.

Las interfaces de solo lectura implementadas por colecciones mutables están aún más abajo en la escala de seguridad, pero son rápidas. Simplemente puede convertir la Lista <> como IReadOnlyList <>, lo que podría hacer en su ejemplo como IReadOnlyList lst = a. Estas son mis preferencias para el código interno: todavía obtienes seguridad de tipo estático, simplemente no estás protegido contra código o código malicioso que usa verificaciones de tipo y descarta imprudentemente (pero eso se puede evitar mediante revisiones de código en mi experiencia). Nunca he sido mordido por esta elección, pero es menos seguro que las dos opciones anteriores. Por el lado positivo, no incurre en asignaciones y es más rápido. Si suele hacer esto, puede definir un método de extensión para realizar el upcast (los lanzamientos pueden ser inseguros en C# porque no solo hacen cambios seguros, sino que posiblemente fallan los downcasts y las conversiones definidas por el usuario, por lo que es bueno idea para evitar lanzamientos explícitos donde sea que puedas).

Tenga en cuenta que en todos los casos, solo la secuencia en sí misma es de solo lectura. Los objetos subyacentes no se ven afectados (por ejemplo, una int o cadena son inmutables, pero los objetos más complicados pueden ser o no).

Cuestiones relacionadas