C # Chuyển biểu thức trả về kết quả khác nhau


13

Tôi đã chuyển sang C # 8 trong một trong những dự án của mình. Và tôi đã chuyển tất cả các switchphát biểu của mình sang các biểu thức. Tuy nhiên tôi phát hiện ra rằng dự án của tôi bắt đầu hoạt động khác đi và tôi đã phát hiện ra rằng đó là do switchbiểu hiện. Hãy lấy mã này làm ví dụ

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

Tôi đã viết kết quả dưới dạng một nhận xét, nhưng tl; dr khi sử dụng công tắc cổ điển, truyền giá trị trả về giá trị trong Loại dự kiến, nhưng khi sử dụng biểu thức chuyển đổi, nó trả về loại "Double", dẫn đến khác nhau byte[]khi nhận được byte của giá trị.

Sự khác biệt giữa hai là gì? Tôi nhớ cái gì


1
Tôi không thể giải thích chính xác lý do tại sao và làm thế nào điều này xảy ra nhưng nếu bạn xem phiên bản dịch ngược mã của bạn tại đây ( gist.github.com/MaDOS/4904683d461d022e4b24f4080009ae5e ) bạn nhận thấy rằng trình biên dịch dường như nhận thấy rằng tất cả các loại có thể trả về của biểu thức sẽ khớp với một đôi và tự động khai báo một gấp đôi nơi nó sẽ lưu trữ bất kỳ kết quả nào sẽ được trả về. ( gist.github.com/MaDOS/
— Robin B

Câu trả lời:


17

Trong biểu mẫu câu lệnh chuyển đổi của bạn , mỗi nhánh sẽ trả về một giá trị trực tiếp. Nó chuyển đổi trực tiếp từ kiểu số sang object, vì đó thực sự là kiểu trả về của phương thức.

Biểu thức chuyển đổi của bạn là hơi khác nhau. Đầu tiên, nó trích xuất một kết quả từ biểu thức chuyển đổi, sau đó chuyển đổi kết quả đó thành kiểu trả về được khai báo. Vì vậy, loại biểu thức chuyển đổi là gì? Đây là loại "tốt nhất" trong số tất cả các loại biểu thức riêng lẻ trong nhánh của biểu thức chuyển đổi.

Tất cả các loại đó có thể được chuyển đổi hoàn toàn thành double(một trong những loại chính nó), vì vậy đó là loại tốt nhất. Vì vậy, phương thức biểu thức chuyển đổi của bạn tương đương với:

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;
}

Bạn có thể thấy "loại tốt nhất" này mà không cần sử dụng biểu thức chuyển đổi, sử dụng các mảng được gõ ngầm:

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

Ở đây loại arrayđược suy ra double[].

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookie và Chính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.