Home > Blockchain >  Convert switch statement to switch expression
Convert switch statement to switch expression

Time:05-15

I converted a switch statement into an expression and expected value to have the same type. However the expression returns decimal type instead of int.

using System;
                    
public class Program
{
    public enum SomeType
    {
        INT32,
        DECIMAL
    }
    
    public static void Main()
    {
        _ = Enum.TryParse("INT32", out SomeType paramType);
        
        object? value = null;
        
        // 
        
        value = paramType switch
        {
                SomeType.DECIMAL => (decimal)2.0,
                SomeType.INT32 => (int)1,
                _ => throw new ArgumentOutOfRangeException($"Not expected type.")
        };
        
        Console.WriteLine(value);
        Console.WriteLine(value.GetType().ToString());
        
        value = null;
        
        switch(paramType)
        {
            case SomeType.DECIMAL:
                value = (decimal)2.0;
                break;
            case SomeType.INT32:
                value = (int)1;
                break;
            default:
                throw new ArgumentOutOfRangeException($"Not expected type.");
        }
        
        Console.WriteLine(value);
        Console.WriteLine(value.GetType().ToString());
    }
}

Results:

1
System.Decimal

1
System.Int32

Why is that? You can try it here: https://dotnetfiddle.net/

CodePudding user response:

The switch expression tries to find the "best" result type, in the same way that an implicitly-typed array does.

Given types int and decimal, the best result type is decimal, because while there's an implicit conversion from int to decimal, there's only an explicit conversion from decimal to int (as it loses information).

The switch expression will implicit convert the result of the selected "branch" to that type, regardless of type of the variable that it's being assigned to.

In other words, your code is equivalent to:

object? value = null;

// The compiler selects tmp here based as the best result type
// between int and decimal
decimal tmp = paramType switch { ... };

// Now the assignment performs any conversions required to assign
// to the variable
value = tmp;

If you wanted to make the result type of the switch expression object, you need to make sure that one of the branches returns object. For example:

value = paramType switch
{
    SomeType.DECIMAL => (object) 2.0m,
    SomeType.INT32 => 1,
    _ => throw new ArgumentOutOfRangeException($"Not expected type.")
};

(The use of 2.0m is just to demonstrate a better way of coming up with a decimal than casting a double value...)

Now the result type is object, and in your sample code you end up with a boxed int instead of the int value being converted to decimal before boxing.

  •  Tags:  
  • c#
  • Related