Прежде чем начать критиковать и указывать на меня §8.7.2 из C # спецификация , внимательно прочитайте:)
Мы все знаем, как выглядит переключатель в C #. Итак, рассмотрим класс MainWindow
с "противным" баром методом
static int barCounter = 0;
public static int Bar()
{
return ++barCounter;
}
Где-то в этом классе у нас есть такой код
Action switchCode = () =>
{
switch (Bar())
{
case 1:
Console.WriteLine("First");
break;
case 2:
Console.WriteLine("Second");
break;
}
};
switchCode();
switchCode();
В окне консоли мы увидим
First
Second
Используя выражения в C #, мы могли бы делать то же самое - писать много одинакового кода
var switchValue = Expression.Call(typeof(MainWindow).GetMethod("Bar"));
var WriteLine = typeof(Console).GetMethod("WriteLine", new Type[] { typeof(String) });
var @switch = Expression.Switch(switchValue,
Expression.SwitchCase(
Expression.Call(WriteLine, Expression.Constant("First")),
Expression.Constant(1)
),
Expression.SwitchCase(
Expression.Call(WriteLine, Expression.Constant("Second")),
Expression.Constant(2)
)
);
Action switchCode = Expression.Lambda<Action>(@switch).Compile();
switchCode();
switchCode();
В DebugView мы могли видеть «код позади» этого выражения
.Switch (.Call WpfApplication1.MainWindow.Bar()) {
.Case (1):
.Call System.Console.WriteLine("First")
.Case (2):
.Call System.Console.WriteLine("Second")
}
Эмм, а что если мы используем Expression.Call
вместо Expression.Constant
?
public static bool foo1() { return false; }
public static bool foo2() { return true; }
// .....
var foo1 = Ex.Call(typeof(MainWindow).GetMethod("foo1"));
var foo2 = Ex.Call(typeof(MainWindow).GetMethod("foo2"));
var switchValue = Ex.Call(typeof(MainWindow).GetMethod("Bar"));
var WriteLine = typeof(Console).GetMethod("WriteLine", new Type[] { typeof(String) });
var @switch = Ex.Switch(Ex.Constant(true),
Ex.SwitchCase(
Ex.Call(WriteLine, Ex.Constant("First")),
foo1
),
Ex.SwitchCase(
Ex.Call(WriteLine, Ex.Constant("OK!")),
Ex.Equal(switchValue, Ex.Constant(2))
),
Ex.SwitchCase(
Ex.Call(WriteLine, Ex.Constant("Second")),
foo2
)
);
Action switchCode = Ex.Lambda<Action>(@switch).Compile();
switchCode();
switchCode();
Окно консоли показывает, как мы и ожидали
Second
OK!
и DebugView
.Switch (True) {
.Case (.Call WpfApplication1.MainWindow.foo1()):
.Call System.Console.WriteLine("First")
.Case (.Call WpfApplication1.MainWindow.Bar() == 2):
.Call System.Console.WriteLine("OK!")
.Case (.Call WpfApplication1.MainWindow.foo2()):
.Call System.Console.WriteLine("Second")
}
Таким образом, в выражении case можно использовать неконстантное выражение:)
Хорошо, я знаю, что это маленький «грязный» код. Но тут возникает мой вопрос (наконец-то: P):
Есть ли способ расширить функциональность IDE / VisualStudio / компилятора, чтобы сделать это, но с более элегантным кодом?
Примерно так
switch (true)
{
case foo1():
Console.WriteLine("First");
break;
case Bar() == 2:
Console.WriteLine("OK!");
break;
case foo2():
Console.WriteLine("Second");
break;
}
Я знаю, что это будет какое-то расширение, и код будет не таким (не та же производительность). Но мне интересно, возможно ли вообще «изменить» код «на лету», как анонимная функция, или возвращаемая прибыль - это преобразование во вложенный класс.
Я надеюсь, что кто-то прочитает текст выше и оставит некоторую подсказку.