翼度科技»论坛 编程开发 .net 查看内容

Net 编译器平台--- Roslyn Scripting APIs

3

主题

3

帖子

9

积分

新手上路

Rank: 1

积分
9
引言

上一篇中.Net 编译器平台 --- Roslyn,介绍了Roslyn的各项功能,包括公开API,使用语法,使用语义,使用工作区等功能。
那么回到上一篇中提到的问题,实现类似这样的功能(以下代码为伪代码):
  1. string scriptText = "int a = 1;int b = 2; return a+b ;";
  2. var result = Script.Run(scriptText);
复制代码
就用到了上一篇提到的 Scripting APIs,还是先了解一下Roslyn提供的 Scripting APIs 有哪些。
官方文档(https://github.com/dotnet/roslyn/blob/main/docs/wiki/Scripting-API-Samples.md) 还是英文版,还是先将他翻译为中文,以下内容为译文。
Scripting APIs Samples

脚本 API 可以让 .NET 应用程序实例化一个 C# 引擎,并针对由宿主提供的对象执行代码片段。以下是使用脚本 API 并进行一些常见示例的入门示例。您也可以查看脚本 API 的源代码。
请注意,作为一个语言模型,我无法提供实时的源代码示例或链接到具体的源代码。但是,您可以参考 Microsoft 的官方文档和示例来了解如何使用脚本 API 并查看相关源代码。
支持的平台

脚本 API 需要桌面版 .NET Framework 4.6+ 或 .NET Core 1.1(自 Roslyn v2.0.0-rc3、Visual Studio 2017 RC3 起支持)。
脚本 API 无法在通用 Windows 应用程序和 .NET Native 中使用,因为应用程序模型不支持在运行时加载生成的代码。
开始准备

安装 Scripting API NuGet 包:
  1. Install-Package Microsoft.CodeAnalysis.CSharp.Scripting
复制代码
示例代码

以下示例代码中需要添加引用 using Microsoft.CodeAnalysis.CSharp.Scripting;
应用场景:

  • 评估一个C#表达式(Evaluate a C# expression)
  • 评估一个C#表达式(强类型)(Evaluate a C# expression(strongly-typed))
  • 带错误处理的评估C#表达式(Evaluated a C# expression with error handling)
  • 添加引用(Add references)
  • 添加命名空间和类型导入(Add namespace and type imports)
  • 为脚本参数化(Parameterize a script)
  • 创建和构建一个C#脚本,并多次执行(Create&build a C# script and execute it multiple times)
  • 创建一个指向脚本的委托(Create a delegate to a script)
  • 运行一个C#代码片段并检查定义的脚本变量(Run a C# snippet and inspect defined script variables)
  • 将代码片段链接成一个脚本(Chain code snippets to form a script)
  • 从先前状态继续执行脚本(Continue script execution from a previous state)
  • 创建和分析一个C#脚本(Create and analyze a C# script)
  • 自定义程序集加载(Customize assembly loading)
评估一个C#表达式(Evaluate a C# expression)
  1. object result = await CSharpScript.EvaluateAsync("1 + 2");
复制代码
评估一个C#表达式(强类型)(Evaluate a C# expression(strongly-typed))
  1. int result = await CSharpScript.EvaluateAsync<int>("1 + 2");
复制代码
带错误处理的评估C#表达式(Evaluated a C# expression with error handling)
  1. try
  2. {
  3.     Console.WriteLine(await CSharpScript.EvaluateAsync("2+2"));
  4. }
  5. catch (CompilationErrorException e)
  6. {
  7.     Console.WriteLine(string.Join(Environment.NewLine, e.Diagnostics));
  8. }
复制代码
添加引用(Add references)
  1. var result = await CSharpScript.EvaluateAsync("System.Net.Dns.GetHostName()",
  2. ScriptOptions.Default.WithReferences(typeof(System.Net.Dns).Assembly));
复制代码
添加命名空间和类型导入(Add namespace and type imports)

在下面的代码中,WithImports("System.IO") 将 using System.IO; 添加到脚本选项中,使得可以在脚本代码中直接引用 System.IO 命名空间的类型,而无需使用限定符。
  1. var result = await CSharpScript.EvaluateAsync("Directory.GetCurrentDirectory()"),
  2.                                 ScriptOptions.Default.WithImports("System.IO"));
复制代码
同样地,WithImports("System.Math") 将 using static System.Math; 添加到脚本选项中,使得可以在脚本代码中直接引用 System.Math 类型的成员,而无需使用限定符。
  1. var result = await CSharpScript.EvaluateAsync("Sqrt(2)",
  2.                                 ScriptOptions.Default.WithImports("System.Math"));
复制代码
为脚本参数化(Parameterize a script)
  1. public class Globals
  2. {
  3.     public int X;
  4.     public int Y;
  5. }
  6. var globals = new Globals { X = 1, Y = 2 };
  7. Console.WriteLine(await CSharpScript.EvaluateAsync<int>("X+Y", globals: globals));
复制代码
:::tip{title="提示"}
目前,Globals 类型必须在从文件加载的程序集中定义。如果程序集在内存中(包括在交互式窗口中执行示例时),脚本将无法访问该类型。请参阅此处的问题。
:::
创建和构建一个C#脚本,并多次执行(Create&build a C# script and execute it multiple times)
  1. var script = CSharpScript.Create<int>("X*Y", globalsType: typeof(Globals));
  2. script.Compile();
  3. for (int i = 0; i < 10; i++)
  4. {
  5.     Console.WriteLine((await script.RunAsync(new Globals { X = i, Y = i })).ReturnValue);
  6. }
复制代码
创建一个脚本的委托(Create a delegate to a script)

该委托不会保持编译资源(语法树等)处于活动状态。
  1. var script = CSharpScript.Create<int>("X*Y", globalsType: typeof(Globals));
  2. ScriptRunner<int> runner = script.CreateDelegate();
  3. for (int i = 0; i < 10; i++)
  4. {
  5.     Console.WriteLine(await runner(new Globals { X = i, Y = i }));
  6. }
复制代码
运行一个C#代码片段并检查定义的脚本变量(Run a C# snippet and inspect defined script variables)
  1. var state = await CSharpScript.RunAsync<int>("int answer = 42;");
  2. foreach (var variable in state.Variables)
  3.      Console.WriteLine($"{variable.Name} = {variable.Value} of type {variable.Type}");
复制代码
将代码片段链接成一个脚本(Chain code snippets to form a script)
  1. var script = CSharpScript.
  2.             Create<int>("int x = 1;").
  3.             ContinueWith("int y = 2;").
  4.             ContinueWith("x + y");
  5. Console.WriteLine((await script.RunAsync()).ReturnValue);
复制代码
从先前状态继续执行脚本(Continue script execution from a previous state)
  1. var state = await CSharpScript.RunAsync("int x = 1;");
  2. state = await state.ContinueWithAsync("int y = 2;");
  3. state = await state.ContinueWithAsync("x+y");
  4. Console.WriteLine(state.ReturnValue);
复制代码
创建和分析一个C#脚本(Create and analyze a C# script)
  1. using Microsoft.CodeAnalysis;
  2. var script = CSharpScript.Create<int>("3");
  3. Compilation compilation = script.GetCompilation();
  4. //do stuff
复制代码
编译(Compilation)提供了对完整的 Roslyn API 集合的访问。
自定义程序集加载(Customize assembly loading)
  1. using Microsoft.CodeAnalysis.Scripting.Hosting;
  2. using (var loader = new InteractiveAssemblyLoader())
  3. {
  4.     var script = CSharpScript.Create<int>("1", assemblyLoader: loader);
  5.     //do stuff
  6. }
复制代码
参考
https://github.com/dotnet/roslyn/blob/main/docs/wiki/Scripting-API-Samples.md

来源:https://www.cnblogs.com/pandefu/archive/2023/07/08/17536280.html
免责声明:由于采集信息均来自互联网,如果侵犯了您的权益,请联系我们【E-Mail:cb@itdo.tech】 我们会及时删除侵权内容,谢谢合作!

举报 回复 使用道具