Черкашин Александр

Черкашин Александр

Разработчик

© 2020

C# Interactive - REPL

Несколько лет назад я заметил, что в Visual Studio появилась новая окошко “C# Interactive”. Eщё тогда я стал догадываться, что это REPL, однако только недавно решил разобраться, что оно из себя представляет и в каких случаях может быть полезно. Прежде чем мы перейдём, к “С# Interactive” давайте кратко обсудим, что же такое REPL

Что такое REPL?

Repl meme

REPL или “read-eval-print loop” - это интерактивная среда разработки (в командной строке), в которой пользователь вводит выражение на языке программирования, а REPL, в свою очередь, считывает (Read) его, выполняет (Eval) и отображает результат (Print), а затем этот процесс снова повторяется (Loop). Всё просто, не так ли? А чтобы было ещё проще вот небольшой пример.

Repl example

Аббревиатура REPL сложилась из названий функций языка LISP, с помощью которых REPL собственно и был реализован. Примерно вот так выглядит REPL на языке LISP:

(loop (print (eval (read))))

REPL в C# появился вместе с Roslyn и благодаря ему, так как Rolsyn изначально разрабатывался с целью предоставления разработчикам API для работы с компилятором. Подробнее об истории появления Rolsyn и о способах его использования можно почитать здесь. Там же в данной статье вы можете найти упрощенный способ реализации REPL на C#.

class Program 
{    
    static void Main(string[] args)    
    {        
        ScriptState<object> scriptState = null;

        while (true)        
        {            
            Console.Write("* ");
            var input = Console.ReadLine();
            scriptState = scriptState == null ?
                CSharpScript.RunAsync(input, ScriptOptions.Default.AddImports("System")).Result : 
                scriptState.ContinueWithAsync(input).Result;
        }

        Console.ReadLine();
    }
}

Для чего нужен REPL?

Теперь вы знаете, что такое REPL, но я думаю, сейчас в вашей голове примерно следующие мысли “Окей, REPL, круто, а зачем?”. И это самый главный вопрос, ведь каждый инструмент должен решать какие-то проблемы. В нашем случае, REPL позволяет нам мгновенно увидеть результат выполнения кода, без ожидания его компиляции. К тому же вам не нужно создавать новый проект, чтобы протестировать там пару строк кода (У меня целое кладбище таких проектов).

Вы можете использовать REPL, чтобы ознакомиться или поиграться с API, если не уверены в том, как он работает. Давайте наконец-то откроем Visual Studio (если вы используете Rider, то там тоже есть окно “C# Interactive”) и запустим REPL, его можно найти по пути “View > Other Windows > C# Interactive”.

C# Interactive Path

Теперь давайте представим, что мы забыли, мутирует ли объект метод Concat типа List<int>. Тут нам и поможет REPL.

List concat example

Как видно из примера, метод Contact не мутирует существующий список, а возвращает новый, в котором содержатся элементы списков list1, list2. Необходимо подчеркнуть тот факт, что для того чтобы увидеть результат выполнения выражения, нужно чтобы оно не оканчивалось точкой с запятой, иначе результат выведен не будет. Как вы могли заметить, в C# Interactive работает привычный нам IntelliSense, что гораздо упрощает работу.

К счастью, это не все возможности C# Interactive, вы можете использовать его также для изучения сторонних библиотек. Однако, он не позволяет напрямую работать с менеджером пакетов Nuget, поэтому необходимо предварительно скачать нужную вам библиотеку или, если вам необходимо изучить библиотеку которая используется в вашем проекте, можно просто указать путь к ней следующим образом:

#r "...\path\library.dll"

Давайте посмотрим как можно использовать C# Interactive для изучения API библиотеки Octokit.

Octokit usage

Также нужно отметить, что вам не обязательно запускать Visual Studio, чтобы использовать REPL. Вы можете запустить Developer Command Prompt for VS и выполнить команду csi.

Usage csi util

C# Repl доступен не только на Windows. На Linux и Mac может использоваться Mono C# Repl.

DotNet Script

C# Interactive является не единственным REPL окружением для C#, существует ещё минимум 2:

Данные окружения позволяют работать с менеджером пакетов Nuget. Но в данной статье я рассмотрю только DotNet-Script.

Давайте запустим тот же самый пример с библиотекой Octokit, используя DotNet Script (об установке dotnet script можно почитать здесь).

DotNet Script

Для запуска dotnet script необходимо запустить в консоли dotnet script или dotnet-script. Как вы уже заметили из примера, для подключения библиотеки из Nuget используется следующая запись: #r "nuget: <library>, <version>", в нашем случае - это #r "nuget: Octokit, 0.48.0". Первый запуск команды займет некоторое время, так как будет происходить скачивание библиотеки, но в дальнейшем, запуск команды будет занимать гораздо меньше времени, так как библиотека будет закэширована.

DotNet Script использует .net core и поэтому является кросплатформенным, благодаря чему вы можете запустить его на любой платформе.

Однако, чтобы получить intellisense для dotnet script вам необходимо использовать текстовый редактор, поддерживающий OmniSharp. Я покажу, как это сделать, на примере уже знакомого нам примера с Octokit в Visual Studio Code. Для начала нам нужно инициализировать новый проект dotnet script с помощью команды dotnet script init.

Инициализация проекта DotNet Script

Затем необходимо установить C# Extension для Visual Studio Code. После чего необходимо вставить уже знакомый нам пример в файл main.csx.

#!/usr/bin/env dotnet-script
#r "nuget: Octokit, 0.48.0"
using Octokit;
var github = new GitHubClient(new ProductHeaderValue("CherkashinBlogPost"));
var user = await github.User.Get("acherkashin");
Console.WriteLine($"{user.Followers} folks follow acherkashin");
Console.WriteLine(user.Blog);

var pullRequests = await github.PullRequest.GetAllForRepository("storybookjs", "storybook");
Console.WriteLine(pullRequests.Count());

var lastPR = pullRequests.Where(x => x.CreatedAt > DateTimeOffset.Now.Subtract(TimeSpan.FromDays(2)));
foreach(var q in lastPR) {
    Console.WriteLine($"{q.CreatedAt}...{q.User.Login}...{q.Title}");
}

Как вы можете увидеть из скриншота ниже, intellisense в VsCode работает также хорошо как, и в Visual Studio.

IntelliSence в Vs Code

Итак, в начале я сказал, что вам не нужно создавать пустой проект, для того, чтобы протестировать какой-то кусок кода или поиграться с API библиотеки, а в итоге делаю всё с точность до наоборот. Дело в том, что dotnet script представляет собой не только REPL, но и полноценный скриптовый язык. Теперь вы можете писать скрипты на своём любимом языке 😉 и забыть о изучении bash, python, PowerShell… Подробнее об этом вы можете узнать в статье Hitchhiker’s Guide to the C# scripting.

Напоследок хочется отметить, что dotnet scripts также предоставляет возможность отладки. Таким образом вы сможете не только писать скрипты на C#, но и удобно отлаживать их.

Отладка main.csx файла в Visual Studio Code

Если вам понравилась данная тема, то вы можете подробнее познакомиться с dotnet scripts в следующей статье C# REPL for .NET Core 2.0 and #load support from Nuget – dotnet-script 0.16 is out.

Полезные ссылки