0

I am building a Switch expression to match ranges of integers at runtime. Currently I am able to compile and run the equivalent of the following using Expression.SwitchCase:

switch(value)
{
    case 1:
    case 2:
        Console.WriteLine("1 or 2");
        break;
    case 3:
    case 4:
    case 5:
        Console.WriteLine("3, 4 or 5");
        break;
}

My issue being - I have to create a SwitchCase for every constant in the range I wish to match:

Expression.SwitchCase(body, Expression.Constant(1))

Expression.SwitchCase(body, Expression.Constant(2))

Is there a more concise way to achieve this? Is there a way I can replace that constant expression with an expression that evaluates the switched value against a range?. Performance is also of interest, especially if the range is large.

TVOHM
  • 2,740
  • 1
  • 19
  • 29
  • Have you looked at this question [switch-case-can-i-use-a-range-instead-of-a-one-number](https://stackoverflow.com/questions/20147879/switch-case-can-i-use-a-range-instead-of-a-one-number) – Peter B Jan 16 '19 at 10:23
  • Yes, this is exactly the result I want to achieve, but I want to know if it is possible to build at runtime using expressions. – TVOHM Jan 16 '19 at 11:35

1 Answers1

2

You can simplify your code with other overload of Expression.SwitchCase

Just create an array with a test values and convert it to ConstantExpression. Try this example:

var writeLine = typeof(Console).GetMethod("WriteLine", new[] {typeof(string)});

// body of first block
var action1 = Expression.Call(writeLine, Expression.Constant("1 or 2"));
// body of second block
var action2 = Expression.Call(writeLine, Expression.Constant("3, 4 or 5"));

var value = Expression.Parameter(typeof(int), "value");
var body = Expression.Switch(value,
    Expression.SwitchCase(
      action1,
      new[] {1, 2}.Select(i => Expression.Constant(i))),
    Expression.SwitchCase(
      action2, 
      new[] {3, 4, 5}.Select(i => Expression.Constant(i)))
);

var lambda = Expression.Lambda<Action<int>>(body, value);
var method = lambda.Compile();

method(1); // print "1 or 2"
method(4); // print "3, 4 or 5"
Aleks Andreev
  • 7,016
  • 8
  • 29
  • 37