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!