W jednym z moich projektów przełączyłem się na C # 8. I przenosiłem wszystkie moje switch
wypowiedzi na wyrażenia. Jednak dowiedziałem się, że mój projekt zaczął działać inaczej i dowiedziałem się, że to z powodu tego switch
wyrażenia. Pozwala uzyskać na przykład ten kod
class Program
{
public enum DataType
{
Single,
Double,
UInt16,
UInt32,
UInt64,
Int16,
Int32,
Int64,
Byte
}
static void Main(string[] args)
{
dynamic value1 = 5;
dynamic value2 = 6;
var casted = CastToType(value1, DataType.Int16);
var casted1 = CastToTypeExpression(value2, DataType.Int16);
var type = casted.GetType(); // Int16
var type1 = casted1.GetType(); // Double
var bytes = BitConverter.GetBytes(casted); // byte arr with 2 el => [5, 0] <- expected behavior
var bytes1 = BitConverter.GetBytes(casted1); // byte arr with 8 el => [0, 0, 0, 0, 0, 0, 24, 64]
}
public static dynamic CastToType(dynamic value, DataType type)
{
switch (type)
{
case DataType.Byte:
return (byte)value;
case DataType.Double:
return (double)value;
case DataType.Int16:
return (short)value;
case DataType.Int32:
return (int)value;
case DataType.Int64:
return (long)value;
case DataType.Single:
return (float)value;
case DataType.UInt16:
return (ushort)value;
case DataType.UInt32:
return (uint)value;
case DataType.UInt64:
return (ulong)value;
default: throw new InvalidCastException();
}
}
public static dynamic CastToTypeExpression(dynamic value, DataType type)
{
return type switch
{
DataType.Byte => (byte)value,
DataType.Double => (double)value,
DataType.Int16 => (short)value,
DataType.Int32 => (int)value,
DataType.Int64 => (long)value,
DataType.Single => (float)value,
DataType.UInt16 => (ushort)value,
DataType.UInt32 => (uint)value,
DataType.UInt64 => (ulong)value,
_ => throw new InvalidCastException(),
};
}
}
Wynik napisałem jako komentarz, ale tl; dr, gdy używany jest przełącznik klasyczny, rzutowanie wartości zwraca wartość w oczekiwanym typie, ale gdy użyto wyrażenia przełącznika, zwraca on typ „Double”, co powoduje, że byte[]
po otrzymaniu bajty wartości.
Jaka jest różnica między nimi? Za czym tęsknię
Odpowiedzi:
W formularzu instrukcji switch każde ramię zwraca wartość bezpośrednio. Konwertuje bezpośrednio z typu numerycznego na
object
, ponieważ jest to faktycznie typ zwracany przez metodę.Twoja forma wyrażenia przełącznika jest nieco inna. Najpierw wyodrębnia wynik z wyrażenia przełączającego, a następnie konwertuje ten wynik na zadeklarowany typ zwracany. Jaki jest zatem rodzaj wyrażenia przełącznika? Jest to „najlepszy” typ ze wszystkich typów poszczególnych wyrażeń w ramionach wyrażenia przełączającego.
Wszystkie te typy można domyślnie przekonwertować na
double
(który jest jednym z samych typów), więc jest to najlepszy typ. Zatem metoda wyrażenia przełącznika jest równoważna z:Możesz zobaczyć ten „najlepszy typ” bez użycia wyrażenia przełączającego, używając tablic o typie niejawnym:
Tutaj
array
zakłada się, że typdouble[]
.źródło