Script em C # ou execução dinâmica em tempo de execução

Olá, Habr!





Acho que poucas pessoas sabem que o C # tem algo parecido com a avaliação de outras linguagens. Graças à API Roslyn, você pode compilar e executar seu código C # em tempo de execução. Você pode ver um exemplo de uso em minha implementação REPL para C #.





Eu conheci algo como REPL quando toquei em python. Existe algo semelhante no mundo .NET chamado C # Interactive (CSI). Muito útil, mas tem uma grande desvantagem - está incluído nas ferramentas do Visual Studio, portanto, sem instalar o VS, você não será capaz de usá-lo e, para executá-lo sem iniciar o VS, você deve subir para suas profundidades (ou melhor, execute o console C: \ Arquivos de programas (x86) \ Microsoft Visual Studio \ 2019 \ Community \ Common7 \ Tools \ VsDevCmd.bat), que pode não ser uma solução conveniente o suficiente.





Existem também projetos como dotnet-script e cs-script (eles funcionam através de Microsoft.CodeAnalysis.CSharp.Scripting ), mas eles têm uma falha fatal - eles não foram escritos por mim. Então surgiu a ideia de escrever sua própria bicicleta desajeitada, mas com recursos próprios (que também funcionam desajeitadamente) !. Após uma breve pesquisa, meus olhos caíram sobre este milagre: Microsoft.CodeAnalysis.CSharp.Scripting . Uma das vantagens é uma API conveniente, a capacidade de executar código sem classes e namespaces.





Primeiro, você precisa instalar o pacote Microsoft.CodeAnalysis.CSharp.Scripting e fazer usando





using Microsoft.CodeAnalysis.CSharp.Scripting;
using Microsoft.CodeAnalysis.Scripting;
      
      



CSharpScript é uma classe estática que nos ajudará a criar um script, inclui 3 métodos:





  • Create - Script ,





  • RunAsync - , ScriptState





  • EvaluateAsync -





CSharpScript.Create , .





var script = CSharpScript.Create("System.Console.WriteLine(\"Hello from script\")");
script.Compile();
await script.RunAsync();
      
      



E Compile(), .





ScriptOptions, namespace- reference- ( , using static).





  var options = ScriptOptions.Default
            .AddImports("System", "System.IO", "System.Collections.Generic",
                "System.Console", "System.Diagnostics", "System.Dynamic",
                "System.Linq", "System.Text",
                "System.Threading.Tasks")
            .AddReferences("System", "System.Core", "Microsoft.CSharp");

 CSharpScript.Create("Console.WriteLine(\"Hello from script\")", options);
      
      



— ScriptOptions - namespace-. whitelist, , , .





CSharpScript.RunAsync ScriptState, ContinueWithAsync, , ScriptState. , Script. , ReturnValue.





ScriptState state = await CSharpScript.RunAsync("int x = 5;");
state = await state.ContinueWithAsync<int>("x + 1");
Console.WriteLine(state.ReturnValue); // 6
      
      



state , exception





foreach(var variable in state.Variables)
{
	Console.WriteLine($"{variable.Name} - {variable.Value}");
}
      
      



CSharpScript.Create ,





var script = CSharpScript.Create<Func<int,int>>("x => x+1");
Console.WriteLine(await script.CreateDelegate().Invoke(1)); // 2
      
      



, - , CSharpScript.EvaluateAsync ( , )





var deleg = await CSharpScript.EvaluateAsync<Func<int, int>>("x => x * 2");
Console.WriteLine(deleg(5)); // 10
      
      



- ( , , ).





CSharpScript globals globalsType (globalsType , globals), , ( CSharpScript.Create globalsType, script.RunAsync() globals).





var res = await CSharpScript.EvaluateAsync<int>("X+Y", globals: new GlobalValues());
Console.WriteLine(res); // 100

public class GlobalValues 
{
	public int X = 25;
	public int Y = 75;
}
      
      



:





, , . .





Microsoft.CodeAnalysis.CSharp.Scripting, , runtime C# . , , .net .





5 github, :





:





https://github.com/dotnet/roslyn/blob/main/docs/wiki/Scripting-API-Samples.md





https://github.com/dotnet/roslyn/tree/a7319e2bc8cac34c34527031e6204d383d29d4ab/src/Scripting





Espero que meu primeiro artigo não tenha parecido muito chato e eu tenha sido capaz de ajudá-lo de alguma forma.





Tenha um bom dia!








All Articles