EDITAR: se agregó un código de muestra que explora muchas (¿quizás todas?) Formas posibles de iterar sobre la matriz.
Los tipos de enum se consideran "derivados" de int por defecto. Puede elegir derivarlo de uno de los otros tipos de enteros si lo desea, como byte, corto, largo, etc.
En ambos casos, la llamada a Enum.GetValues
devuelve una matriz de objetos ReportStatus.
El uso de la palabra clave var en el primer ciclo le dice al compilador que use el tipo especificado de la matriz, que es ReportStatus, para determinar el tipo de la variable de valor. La implementación de ToString para enums es devolver el nombre de la entrada enum, no el valor entero que representa, por lo que los nombres se están produciendo desde el primer ciclo.
El uso de una variable int en el segundo ciclo hace que los valores devueltos por Enum.GetValues
se conviertan implícitamente de ReportStatus a int. Llamar a ToString en un int., Por supuesto, devolverá una cadena que representa el valor entero. La conversión implícita es lo que causa la diferencia en el comportamiento.
ACTUALIZACIÓN: Como otros han señalado, la función Enum.GetValues devuelve un objeto escrito como matriz, y como resultado es un enumerable de tipos de objeto, no tipos de estado de informe.
En cualquier caso, el resultado final es el mismo si la iteración en matriz o ReportStatus []:
class Program
{
enum ReportStatus
{
Assigned = 1,
Analyzed = 2,
Written = 3,
Reviewed = 4,
Finished = 5,
}
static void Main(string[] args)
{
WriteValues(Enum.GetValues(typeof(ReportStatus)));
ReportStatus[] values = new ReportStatus[] {
ReportStatus.Assigned,
ReportStatus.Analyzed,
ReportStatus.Written,
ReportStatus.Reviewed,
ReportStatus.Finished,
};
WriteValues(values);
}
static void WriteValues(Array values)
{
foreach (var value in values)
{
Console.WriteLine(value);
}
foreach (int value in values)
{
Console.WriteLine(value);
}
}
static void WriteValues(ReportStatus[] values)
{
foreach (var value in values)
{
Console.WriteLine(value);
}
foreach (int value in values)
{
Console.WriteLine(value);
}
}
}
Sólo por poco de diversión extra, he añadido algo de código a continuación demuestra varias maneras diferentes de la iteración en la especificada array con un ciclo foreach, que incluye comentarios que describen en detalle lo que está sucediendo en cada caso.
class Program
{
enum ReportStatus
{
Assigned = 1,
Analyzed = 2,
Written = 3,
Reviewed = 4,
Finished = 5,
}
static void Main(string[] args)
{
Array values = Enum.GetValues(typeof(ReportStatus));
Console.WriteLine("Type of array: {0}", values.GetType().FullName);
// Case 1: iterating over values as System.Array, loop variable is of type System.Object
// The foreach loop uses an IEnumerator obtained from System.Array.
// The IEnumerator's Current property uses the System.Array.GetValue method to retrieve the current value, which uses the TypedReference.InternalToObject function.
// The value variable is passed to Console.WriteLine(System.Object).
// Summary: 0 box operations, 0 unbox operations, 1 usage of TypedReference
Console.WriteLine("foreach (object value in values)");
foreach (object value in values)
{
Console.WriteLine(value);
}
// Case 2: iterating over values as System.Array, loop variable is of type ReportStatus
// The foreach loop uses an IEnumerator obtained from System.Array.
// The IEnumerator's Current property uses the System.Array.GetValue method to retrieve the current value, which uses the TypedReference.InternalToObject function.
// The current value is immediatly unboxed as ReportStatus to be assigned to the loop variable, value.
// The value variable is then boxed again so that it can be passed to Console.WriteLine(System.Object).
// Summary: 1 box operation, 1 unbox operation, 1 usage of TypedReference
Console.WriteLine("foreach (ReportStatus value in values)");
foreach (ReportStatus value in values)
{
Console.WriteLine(value);
}
// Case 3: iterating over values as System.Array, loop variable is of type System.Int32.
// The foreach loop uses an IEnumerator obtained from System.Array.
// The IEnumerator's Current property uses the System.Array.GetValue method to retrieve the current value, which uses the TypedReference.InternalToObject function.
// The current value is immediatly unboxed as System.Int32 to be assigned to the loop variable, value.
// The value variable is passed to Console.WriteLine(System.Int32).
// Summary: 0 box operations, 1 unbox operation, 1 usage of TypedReference
Console.WriteLine("foreach (int value in values)");
foreach (int value in values)
{
Console.WriteLine(value);
}
// Case 4: iterating over values as ReportStatus[], loop variable is of type System.Object.
// The foreach loop is compiled as a simple for loop; it does not use an enumerator.
// On each iteration, the current element of the array is assigned to the loop variable, value.
// At that time, the current ReportStatus value is boxed as System.Object.
// The value variable is passed to Console.WriteLine(System.Object).
// Summary: 1 box operation, 0 unbox operations
Console.WriteLine("foreach (object value in (ReportStatus[])values)");
foreach (object value in (ReportStatus[])values)
{
Console.WriteLine(value);
}
// Case 5: iterating over values as ReportStatus[], loop variable is of type ReportStatus.
// The foreach loop is compiled as a simple for loop; it does not use an enumerator.
// On each iteration, the current element of the array is assigned to the loop variable, value.
// The value variable is then boxed so that it can be passed to Console.WriteLine(System.Object).
// Summary: 1 box operation, 0 unbox operations
Console.WriteLine("foreach (ReportStatus value in (ReportStatus[])values)");
foreach (ReportStatus value in (ReportStatus[])values)
{
Console.WriteLine(value);
}
// Case 6: iterating over values as ReportStatus[], loop variable is of type System.Int32.
// The foreach loop is compiled as a simple for loop; it does not use an enumerator.
// On each iteration, the current element of the array is assigned to the loop variable, value.
// The value variable is passed to Console.WriteLine(System.Int32).
// Summary: 0 box operations, 0 unbox operations
Console.WriteLine("foreach (int value in (ReportStatus[])values)");
foreach (int value in (ReportStatus[])values)
{
Console.WriteLine(value);
}
// Case 7: The compiler evaluates var to System.Object. This is equivalent to case #1.
Console.WriteLine("foreach (var value in values)");
foreach (var value in values)
{
Console.WriteLine(value);
}
// Case 8: The compiler evaluates var to ReportStatus. This is equivalent to case #5.
Console.WriteLine("foreach (var value in (ReportStatus[])values)");
foreach (var value in (ReportStatus[])values)
{
Console.WriteLine(value);
}
}
}
- He actualizado mis comentarios en el ejemplo anterior; al hacer una doble comprobación, vi que el método System.Array.GetValue realmente utiliza la clase TypedReference para extraer un elemento de la matriz y devolverlo como System.Object. Originalmente había escrito que había una operación de boxeo allí, pero técnicamente no es el caso. No estoy seguro de cuál es la comparación de una operación de cuadro con una llamada a TypedReference.InternalToObject; Supongo que depende de la implementación de CLR. A pesar de todo, creo que los detalles son más o menos correctos ahora.
¿Qué dice el tipo de Visual Studio cuando pasas el mouse sobre la 'var'? – ChrisF
¡No tengo idea, pero me parece muy útil! – sbenderli
@sbenderli - Acabo de comprobar y es 'System.Object', que probablemente de alguna manera explica la diferencia. – ChrisF