C#スイッチ式が異なる結果を返す


13

プロジェクトの1つでC#8に切り替えました。そして、私はすべてのswitch発言を表現に移しています。しかし、自分のプロジェクトが別の方法で機能し始めたこと、そしてそれがswitch表現のせいであることがわかりました。たとえば、このコードを取得しましょう

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(),
        };
    }
}

結果をコメントとして書きましたが、クラシックスイッチを使用した場合のtl; drは、値をキャストすると期待されるTypeの値が返されますが、スイッチ式を使用すると「Double」のタイプが返さbyte[]れるため、値のバイト。

2つの違いは何ですか?私は何を見逃していますか?


1
なぜ、どのように発生するかを正確に説明することはできませんが、ここでコードの逆コンパイルバージョンを確認すると(gist.github.com/MaDOS/4904683d461d022e4b24f4080009ae5e)、コンパイラはすべての可能な戻り型に気付いているようです式のはdoubleに適合し、返される結果を格納する場所でdoubleを自動的に宣言します。(gist.github.com/MaDOS/...
ロビンB

回答:


17

switch ステートメントフォームでは、各アームが直接値を返します。数値型から直接に変換していますobject。これは、事実上、メソッドの戻り値の型だからです。

あなたのスイッチ形式は少し異なります。最初にスイッチ式から結果を抽出し、次にその結果を宣言された戻り値の型に変換します。では、スイッチ式のタイプは何ですか?これは、スイッチ式の腕の中にある個々の式のすべてのタイプからの「最良の」タイプです。

これらのタイプはすべて暗黙的にdouble(タイプ自体の1つに)変換されるため、これが最良のタイプです。したがって、スイッチ式メソッドは次と同等です。

public static dynamic CastToTypeExpression(dynamic value, DataType type)
{
    double result = 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(),
    };
    return result;
}

暗黙的に型指定された配列を使用して、スイッチ式を使用せずにこの「最良の型」を確認できます。

var array = new[]
{
    (byte) 0, 0.0, (short) 0, 0,
    0L, 0f, (ushort) 0, 0U, 0UL
};

ここでのタイプはarrayと推定されますdouble[]

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.