C# 源代码生成器
-
什么是源生成器
-
源生成器允许执行两个主要操作
-
Microsoft 文档模型图示
-
常见方案
-
源生成器的使用
-
1、创建 .NET控制台应用程序
-
2、创建源生成器项目
-
3、在控制台程序中使用生成器项目
什么是源生成器
源生成器
是由
.NET Compiler Platform(“Roslyn”)
SDK 附带。
通过源生成器,C# 开发人员可以在编译用户代码时检查用户代码。 生成器可以动态创建新的 C# 源文件,这些文件将添加到用户的编译中。 这样,代码可以在编译期间运行。
它会检查你的程序以生成与其余代码一起编译的其他源文件
。
源生成器允许执行两个主要操作
1、检索表示正在编译的所有用户代码的编译对象。 可以检查此对象,并且可以编写适用于正在编译的代码的语法和语义模型的代码,就像现在使用分析器一样。
2、生成可在编译过程中添加到编译对象的 C# 源文件。 也就是说,在编译代码时,可以提供其他源代码作为编译的输入。
结合使用这两项操作能充分发挥源生成器的强大功能。 可以使用编译器在编译时构建的丰富元数据检查用户代码。 然后,生成器将 C# 代码发送回基于已分析数据的同一编译。 如果你熟悉 Roslyn 分析器,可以将源生成器视为可发出 C# 源代码的分析器。
Microsoft 文档模型图示
源生成器作为编译阶段运行
源生成器是由编译器与任何分析器一起加载的 .NET Standard 2.0 程序集。 它在可以加载和运行 .NET Standard 组件的环境中使用。
目前只有 .NET Standard 2.0 程序集可以用作源生成器。
常见方案
-
运行时反射
-
处理 MSBuild 任务
-
交织中间语言 (IL)
可用于检查用户代码,并基于当今技术所使用的分析生成信息或代码。
详细内容参考Microsoft 文档
源生成器的使用
1、创建 .NET控制台应用程序
不使用顶级语句, 经典格式是必需的
强行使用顶级语句会报:
错误 CS0759 没有为分部方法“Program.HelloFrom(string)”的实现声明找到定义声明
方法未声明的错误
namespace SourceCodeConsole
{
public partial class Program
{
static void Main(string[] args)
{
HelloFrom("Generated Code");
}
static partial void HelloFrom(string name);
}
}
2、创建源生成器项目
引入NuGet包:
Microsoft.CodeAnalysis.CSharp
Microsoft.CodeAnalysis.Analyzers
继承 ISourceGenerator 并实现接口方法,也要为实现类添加
[Generator]
特性支持
using Microsoft.CodeAnalysis;
using System.Diagnostics;
namespace HelloSourceCode
{
[Generator]
public class HelloSourceGenerator : ISourceGenerator
{
public void Execute(GeneratorExecutionContext context)
{
// 找到主方法
var mainMethod = context.Compilation.GetEntryPoint(context.CancellationToken);
// 构建源代码
string source = $@"// <auto-generated/>
using System;
namespace {mainMethod.ContainingNamespace.ToDisplayString()}
{{
public static partial class {mainMethod.ContainingType.Name}
{{
static partial void HelloFrom(string name) =>
Console.WriteLine($""Generator says: Hi from '{{name}}'"");
}}
}}
";
var typeName = mainMethod.ContainingType.Name;
// 将源代码添加到编译中
context.AddSource($"{typeName}.g.cs", source);
}
public void Initialize(GeneratorInitializationContext context)
{
// 不需要初始化
// 附加调试器进程
//if (!Debugger.IsAttached)
//{
// Debugger.Launch();
//}
}
}
}
从
context
对象中,我们可以访问编译的入口点或
Main
方法。 mainMethod 实例是一个
IMethodSymbol
,它表示一个方法或类似方法的符号(包括构造函数、析构函数、运算符或属性/事件访问器)。
Microsoft.CodeAnalysis.Compilation.GetEntryPoint
方法返回程序的入口点的
IMethodSymbol
。 其他方法使你可以查找项目中的任何方法符号。 在此对象中,我们可以推理包含的命名空间(如果存在)和类型。 此示例中的
source
是一个内插字符串,它对要生成的源代码进行模板化,其中内插的缺口填充了包含的命名空间和类型信息。 使用提示名称将
source
添加到
context
。 对于此示例,生成器创建一个新的生成的源文件,其中包含控制台应用程序中
partial
方法的实现。 可以编写源生成器来添加任何喜欢的源。
GeneratorExecutionContext.AddSource
方法中的
hintName
参数可以是任何唯一名称。 通常为该名称提供显式 C# 文件扩展名,例如
".g.cs"
或
".generated.cs"
。 该文件名有助于将文件标识为正在生成源。
关于
Initialize
方法一般是不用初始化的,上面可以看到我是写了一段代码的,作用是进入调试,这样做的主要原因是,不进行附加是无法进行调试的
3、在控制台程序中使用生成器项目
<ItemGroup>
<ProjectReference Include="..\HelloSourceCode\HelloSourceCode.csproj"
OutputItemType="Analyzer"
ReferenceOutputAssembly="false" />
</ItemGroup>
新引用不是传统的项目引用,必须手动编辑以包含 OutputItemType 和 ReferenceOutputAssembly 属性。
-
-
运行结果
-
-
查看生成的代码
结语
本文学术内容皆引用于 Microsoft 文档
部分详细内容,本篇不再说明,Microsoft 文档说得很明确:文档地址
https://learn.microsoft.com/zh-cn/dotnet/csharp/roslyn-sdk/
JavaScript中的几个tip,有用……
1、JavaScript中的继承 在 JavaScript中实现继承的方法是:将子类的 prototype 属性设置为父类的对象。 例如,我有一个 Basket 类,继承 Hashtable 类: java代码: Basket.prototype = new Hashtable();
Basket.prot
spring boot post参数 springboot post单个参数
前提:客户端提交header,设置Content-Type类型为:application/json,这一项设置可有可无,但是为了避免出现其他不可预料的问题,事先说明,建议添加这一项请求头header设置。 一、使用@RequestParam@RequestMapping(value = "/login", method = RequestMethod.POST)
public M