C# - Apresentando a Scripting API (Roslyn)


 Você sabia que pode criar scripts na linguagem C# ? E que ela possui uma API de Scripts ?

Embora seja muito pouco comentado o recurso para criar Scripts na linguagem C# não é uma novidade.

Desde o lançamento do compilador Roslyn (2015/2016) a linguagem C# possui uma API de Scripts que permite que os aplicativos avaliem o código em tempo de execução, fornecendo à API a implementação de uma excelente experiência de script.

Este recurso pode ser usado para avaliar código em tempo de execução e pode ser usado em uma variedade de cenários como por exemplo em um tomador de decisão onde você define um conjunto de regras e em cada regra pode avaliar os parâmetros de entrada e com base nisso, fornecer uma saída.

Para usar este recurso basta instalar no seu projeto o pacote:

Install-Package Microsoft.CodeAnalysis.CSharp.Scripting -Version 3.6.0

Obs: A versão estável atual é a 3.6.0

Após isso é só usar. Veja um exemplo básico a seguir:

using Microsoft.CodeAnalysis.CSharp.Scripting;
using System;
namespace CShp_Scripting1
{
    class Program
    {
        static void Main(string[] args)
        {
            int valor = 0;
            string expressao = "100 * 2 + 80 / 2";
            CSharpScript.EvaluateAsync<int>($"{expressao}")
                .ContinueWith(s => valor = s.Result).Wait();
            Console.WriteLine($"{expressao} = {valor}");
            object resultado = null;
            CSharpScript.EvaluateAsync("System.DateTime.Today.Year")
                .ContinueWith(s => resultado = s.Result).Wait();
            Console.WriteLine($"Hoje = {resultado}");
            Console.ReadLine();
        }
    }
}
 
 

Aqui temos um exemplo de avaliação de expressões.

Podemos usar a avaliação fazendo um tratamento de exceções:

   static void Main(string[] args)
   {
            try
            {
                int valor = 0;
                string expressao = "500 / 2 - 100 * 2 + 50";

                CSharpScript.EvaluateAsync<int>($"{expressao}")
                      .ContinueWith(s => valor = s.Result).Wait();

                 Console.WriteLine($"{expressao} = {valor}");
            }
            catch (CompilationErrorException e)
            {
                Console.WriteLine(string.Join(Environment.NewLine, e.Diagnostics));
            }
            Console.ReadLine();
    }

E também com usar com parâmetros e com tipos:

   public class Escola
    {
        public int numeroDeAlunos;
        public int alunosPorClasse;
    }
    class Program
    {
        static void Main(string[] args)
        {
            var globals = new Escola { numeroDeAlunos = 90, alunosPorClasse = 15 };
            int valor = 0;
            CSharpScript.
                EvaluateAsync<int>("numeroDeAlunos/alunosPorClasse", globals: globals)
                  .ContinueWith(s => valor = s.Result).Wait();            
            Console.WriteLine($"{globals.numeroDeAlunos} / {globals.alunosPorClasse} = {valor}");
            Console.ReadLine();
        }
    }

Aqui estamos enviando os parâmetros para uma expressão e usando-os na lógica do script.

Podemos também criar um script para executar diversas vezes:

    public class Escola
    {
        public int numeroDeAlunos;
        public int alunosPorClasse;
    }
    class Program
    {
        static void Main(string[] args)
        {
            var script = CSharpScript.
                          Create<decimal>("numeroDeAlunos/alunosPorClasse", globalsType: typeof(Escola));
            script.Compile();
            object valor = null;
            for (int i = 100; i < 300; i+=40)
            {
                script.RunAsync(new Escola { numeroDeAlunos = i, alunosPorClasse = 6 })
                    .ContinueWith(s => valor = s.Result.ReturnValue).Wait();

                Console.WriteLine("Numero de classes {valor}");
            };
            Console.ReadLine();
        }
   }

O resultado da execução acima é o seguinte:

Aqui estamos criando um script com parâmetros de um tipo e forçando a sua compilação e a seguir estamos executando diversas vezes o script passando valores para os parâmetros.

Para mais exemplos consulte o repositório no GitHub: https://github.com/dotnet/roslyn

"Porque a lei foi dada por Moisés; a graça e a verdade vieram por Jesus Cristo."
João 1:17

Referências:


José Carlos Macoratti