Translate

jueves, 11 de mayo de 2023

Scripting API de Roslyn

Para instalar la API de Scripting en el proyecto simplemente hay que ejecutar:

Install-Package Microsoft.CodeAnalysis.Scripting -Pre

CSharpScript.EvaluateAsync es probablemente la forma más sencilla de empezar a evaluar expresiones. 


var result = await CSharpScript.EvaluateAsync("5 + 5");

Console.WriteLine(result); // 10


result = await CSharpScript.EvaluateAsync(@"""sample""");

Console.WriteLine(result); // sample


result = await CSharpScript.EvaluateAsync(@"""sample"" + "" string""");

Console.WriteLine(result); // sample string


result = await CSharpScript.EvaluateAsync("int x = 5; int y = 5; x"); //Note the last x is not contained in a proper statement

Console.WriteLine(result); // 5

No todos los scripts devuelven un único valor. Para secuencias de comandos más complejos, es posible que deseemos realizar un seguimiento del estado o inspeccionar diferentes variables. CSharpScript.RunAsync crea y devuelve un objeto ScriptState que nos permite hacer exactamente esto. 


var state = CSharpScript.RunAsync(@"int x = 5; int y = 3; int z = x + y;""");

ScriptVariable x = state.Variables["x"];

ScriptVariable y = state.Variables["y"];


Console.Write($"{x.Name} : {x.Value} : {x.Type} "); // x : 5

Console.Write($"{y.Name} : {y.Value} : {y.Type} "); // y : 3


También podemos mantener el estado de nuestro script y continuar aplicándole cambios con ScriptState.ContinueWith():


var state = CSharpScript.RunAsync(@"int x = 5; int y = 3; int z = x + y;""").Result;

state = state.ContinueWithAsync("x++; y = 1;").Result;

state = state.ContinueWithAsync("x = x + y;").Result;


ScriptVariable x = state.Variables["x"];

ScriptVariable y = state.Variables["y"];


Console.Write($"{x.Name} : {x.Value} : {x.Type} "); // x : 7

Console.Write($"{y.Name} : {y.Value} : {y.Type} "); // y : 1



Podemos agregar referencias a los archivos DLL que nos gustaría usar. Usamos ScriptOptions para proporcionar nuestro script con las MetadataReferences adecuadas.

ScriptOptions scriptOptions = ScriptOptions.Default;

//Add reference to mscorlib
var mscorlib = typeof(System.Object).Assembly;
var systemCore = typeof(System.Linq.Enumerable).Assembly;
scriptOptions = scriptOptions.AddReferences(mscorlib, systemCore);
//Add namespaces
scriptOptions = scriptOptions.AddNamespaces("System");
scriptOptions = scriptOptions.AddNamespaces("System.Linq");
scriptOptions = scriptOptions.AddNamespaces("System.Collections.Generic");

var state = await CSharpScript.RunAsync(@"var x = new List(){1,2,3,4,5};", scriptOptions);
state = await state.ContinueWithAsync("var y = x.Take(3).ToList();");

var y = state.Variables["y"];
var yList = (List)y.Value;
foreach(var val in yList)
{
  Console.Write(val + " "); // Prints 1 2 3
}

Este material es sorprendentemente amplio. El espacio de nombres Microsoft.CodeAnalysis.Scripting está lleno de tipos.