Ещё один Pattern Matching на C# — теперь с построением контекста
Полтора месяца назад я опубликовал статью, посвящённую реализации соспоставления с образцом на C#. В комментарии к статье gBear справедливо отметил отсутствие контекста в кейсах. В первой версии мэтчера я сознательно проигнорировал этот механизм, так как посчитал синтаксические возможности выражений в C# недостаточными для его реализации. Однако, некоторое время спустя я понял, что нужного эффекта можно достичь путём построения Expression вручную. Под катом — реализация полноценного pattern matching.Изначально при реализации сопоставления с образцом мне хотелось сделать синтаксис case-выражения похожим на следующий: s => string.IsNullOrEmpty (s) => 0 К сожалению, в C# это является синтаксически неверным: по сути s => t => s * t Представляет собой функцию в каррированой форме. Второй идеей для case выражения было использование тернарного оператора вроде следующего: s => t? a: b Которое опять-таки невозможно по причине отсутствия в C# типа Unit (для использования в ветке else). Была идея типом для выражения b сделать Expression и передавать туда следующий case, но этому препятствует требование идентичности типов для выражений a и b.В какой-то момент я свыкся с мыслью, что реализовать контекстную связанность мне не удастся и пользовался мэтчингом в том виде, в котором он есть.Однажды в процессе отладки кода, вроде следующего
… {s => s is string, s => ((string)s).Length} … я подумал, что вместо проверки типа is можно проводить преобразование as и проверять результат этого преобразования. Тут меня осенило — ведь это же и будет по сути построением контекста! Не откладывая надолго, я взялся за реализацию.Во второй версии решено было отказаться совсем от реализации Matcher перебором лямбда-функций и использовать только деревья выражений (как в ExprMatcher). Метод Add пришлось сделать типизированым:
public void Add
var matcherExpression = Expression.Block (_caseExpressionsList.Concat (finalExpressions));
return Expression.Lambda
var match = new Matcher
Как и в прошлый раз, буду рад замечаниям/предложениям в комментариях.Спасибо за внимание!