EDIT: aggiunto un codice di esempio che esplora molti (forse tutti?) Possibili modi di iterare sull'array.
I tipi di enum sono considerati "derivati" da int di default. È possibile scegliere di derivarlo da uno degli altri tipi interi se lo si desidera, ad esempio byte, breve, lungo, ecc.
In entrambi i casi, la chiamata a Enum.GetValues
restituisce una matrice di oggetti ReportStatus.
L'utilizzo della parola chiave var nel primo ciclo indica al compilatore di utilizzare il tipo specificato dell'array, che è ReportStatus, per determinare il tipo della variabile valore. L'implementazione di ToString per enumerazione restituisce il nome della voce enum, non il valore intero che rappresenta, motivo per cui i nomi vengono emessi dal primo ciclo.
Utilizzando una variabile int nel secondo ciclo, i valori restituiti da Enum.GetValues
vengono convertiti implicitamente da ReportStatus a int. Chiamare ToString su un int, ovviamente, restituisce una stringa che rappresenta il valore intero. La conversione implicita è ciò che causa la differenza di comportamento.
AGGIORNAMENTO: Come altri hanno sottolineato, la funzione Enum.GetValues restituisce un oggetto digitato come Array e, di conseguenza, è un enumerabile di tipi di oggetto, non di tipi di ReportStatus.
Indipendentemente da ciò, il risultato finale è lo stesso se l'iterazione di Array 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);
}
}
}
Solo per un po 'di divertimento in più, ho aggiunto un po' di codice di seguito dimostrando diversi modi di scorrere il specificato array con un ciclo foreach, compresi i commenti che descrivono in dettaglio cosa succede in ogni 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);
}
}
}
- Aggiornato i miei commenti nell'esempio sopra; dopo un doppio controllo ho visto che il metodo System.Array.GetValue utilizza effettivamente la classe TypedReference per estrarre un elemento dell'array e restituirlo come System.Object. Originariamente avevo scritto che c'era un'operazione di inscatolamento, ma tecnicamente non è il caso. Non sono sicuro di quale sia il confronto tra un'operazione di una casella e una chiamata a TypedReference.InternalToObject; Presumo che dipenda dall'implementazione CLR. Indipendentemente da ciò, credo che i dettagli siano più o meno corretti ora.
Che cosa dice il tipo di Visual Studio quando si passa il mouse su 'var'? – ChrisF
Nessuna idea, ma sembra molto utile! – sbenderli
@sbenderli - Ho appena controllato ed è 'System.Object', che probabilmente spiega in qualche modo la differenza. – ChrisF