Hand.GenerateCore
0.2.0.6
There is a newer version of this package available.
See the version list below for details.
See the version list below for details.
dotnet add package Hand.GenerateCore --version 0.2.0.6
NuGet\Install-Package Hand.GenerateCore -Version 0.2.0.6
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Hand.GenerateCore" Version="0.2.0.6" />
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Hand.GenerateCore" Version="0.2.0.6" />
<PackageReference Include="Hand.GenerateCore" />
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Hand.GenerateCore --version 0.2.0.6
The NuGet Team does not provide support for this client. Please contact its maintainers for support.
#r "nuget: Hand.GenerateCore, 0.2.0.6"
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package Hand.GenerateCore@0.2.0.6
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=Hand.GenerateCore&version=0.2.0.6
#tool nuget:?package=Hand.GenerateCore&version=0.2.0.6
The NuGet Team does not provide support for this client. Please contact its maintainers for support.
SourceGenerator之partial范式
- 封装SourceGenerator常用功能
- partial范式的最佳实践
一、什么是partial范式
- partial关键字允许将一个类或方法分散到多个文件中
- 所以partial是代码生成的一个很好的抓手
- 再配合Attribute特性,可以更准确定位需要生成代码的类或方法
- 对代码按规则自动补足,减少重复代码编写及其可能导致的失误
- 笔者称之为SourceGenerator的partial范式
- 开源项目Hand.GenerateCore用于践行partial范式
二、partial范式的要素
1. 标记定位
- 通过Attribute特性来标记需要代码补足的位置
- Attribute的命名最好与调用的SourceGenerator一致
- 需要生成的类有相应的Attribute也可以增加可读性(有预期该类包含自动生成的代码)
- partial范式通过官方方法SyntaxValueProvider.ForAttributeWithMetadataName来标记定位
2. 节点过滤
- ISyntaxFilter是节点过滤接口
- SyntaxFilter是默认实现,实现按节点类型和是否为partial来过滤
interface ISyntaxFilter
{
bool Match(SyntaxNode node, CancellationToken cancellation = default);
}
class SyntaxFilter(bool isPartial, params SyntaxKind[] kinds)
: ISyntaxFilter
3. 转化源对象
- IGeneratorSource是转化源接口
- GenerateFileName是生成文件名属性
- Generate是生成代码方法
public interface IGeneratorSource
{
string GenerateFileName { get; }
SyntaxGenerator Generate();
}
4. 转化过滤
- 对节点预处理
- 如果不满足生成必要条件返回null会被自动过滤
- ISyntaxTransform是转化接口
- PassTransform是默认实现,直接返回官方对象
- TSource一般实现接口IGeneratorSource
interface IGeneratorTransform<TSource>
{
TSource? Transform(GeneratorAttributeSyntaxContext context, CancellationToken cancellation);
}
class PassTransform : IGeneratorTransform<GeneratorAttributeSyntaxContext>
{
public GeneratorAttributeSyntaxContext Transform(GeneratorAttributeSyntaxContext context, CancellationToken cancellation)
=> context;
}
5. 执行生成
- IGeneratorExecutor是执行接口
- GeneratorExecutor是默认实现,一般可以执行使用
interface IGeneratorExecutor<TSource>
{
void Execute(SourceProductionContext context, TSource source);
}
class GeneratorExecutor<TSource> : IGeneratorExecutor<TSource>
where TSource : IGeneratorSource
{
public virtual void Execute(SourceProductionContext context, TSource source)
{
var cancellation = context.CancellationToken;
if (cancellation.IsCancellationRequested)
return;
var builder = source.Generate();
var code = builder.Build()
.WithGenerated()
.ToFullString();
context.AddSource(source.GenerateFileName, code);
}
}
6. 生成器基类ValuesGenerator
- 通过ValuesGenerator简化代码生成器开发
- 把业务逻辑都提取到TSource中
- filter、transform和executor都会很简单
class ValuesGenerator<TSource>(
string attributeName,
ISyntaxFilter filter,
ISyntaxTransform<TSource> transform,
ISyntaxExecutor<TSource> executor);
三、通过ValuesGenerator实现代码生成器的Case
- 定义类型HelloGenerator继承ValuesGenerator即可
- 另外需要实现HelloGeneratorAttribute、HelloTransform和HelloSource
1. HelloGenerator代码非常简单
- 含义是查找HelloGenerator标记
- 查找含partial修饰的类
- 转化为HelloSource
- 用HelloSource生成代码
public class HelloGenerator()
: ValuesGenerator<HelloSource>(
"GenerateCoreTests.Hello.HelloGeneratorAttribute",
new SyntaxFilter(true, SyntaxKind.ClassDeclaration),
new HelloTransform(),
new GeneratorExecutor<HelloSource>())
{
}
2. HelloGeneratorAttribute非常简单
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)]
public class HelloGeneratorAttribute : Attribute
{
}
3. HelloTransform非常简单
public class HelloTransform : IGeneratorTransform<HelloSource>
{
public HelloSource? Transform(GeneratorAttributeSyntaxContext context, CancellationToken cancellation)
{
if (context.TargetNode is ClassDeclarationSyntax type && context.TargetSymbol is INamedTypeSymbol symbol)
return new(type, symbol);
return null;
}
}
4. HelloSource是比较纯净的业务逻辑
public class HelloSource(ClassDeclarationSyntax type, INamedTypeSymbol symbol)
: IGeneratorSource
{
private readonly ClassDeclarationSyntax _type = type;
private readonly INamedTypeSymbol _symbol = symbol;
public string GenerateFileName
=> $"{_symbol.ToDisplayString()}.Hello.g.cs";
public SyntaxGenerator Generate()
{
var builder = SyntaxGenerator.Clone(_type);
var method = GenerateMethod();
builder.AddMember(method);
return builder;
}
public static MethodDeclarationSyntax GenerateMethod()
{
var name = SyntaxFactory.IdentifierName("name");
var expression = SyntaxGenerator.Interpolation()
.Add("Hello: '")
.Add(name)
.Add("'")
.Build();
return SyntaxGenerator.VoidType.Method("SayHello", SyntaxGenerator.StringType.Parameter(name.Identifier))
.Public()
.Static()
.ToBuilder()
.Add(SyntaxFactory.IdentifierName("Console").Access("WriteLine").Invocation([expression]))
.End();
}
}
5. 测试代码如下
namespace GenerateCoreTests.Hello;
[HelloGenerator]
public partial class HelloTests;
6. 生成代码如下
// <auto-generated/>
namespace GenerateCoreTests.Hello;
partial class HelloTests
{
public static void SayHello(string name)
{
Console.WriteLine($"Hello: '{name}'");
}
}
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net5.0 was computed. net5.0-windows was computed. net6.0 was computed. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 was computed. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 was computed. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
| .NET Core | netcoreapp2.0 was computed. netcoreapp2.1 was computed. netcoreapp2.2 was computed. netcoreapp3.0 was computed. netcoreapp3.1 was computed. |
| .NET Standard | netstandard2.0 is compatible. netstandard2.1 was computed. |
| .NET Framework | net461 was computed. net462 was computed. net463 was computed. net47 was computed. net471 was computed. net472 was computed. net48 was computed. net481 was computed. |
| MonoAndroid | monoandroid was computed. |
| MonoMac | monomac was computed. |
| MonoTouch | monotouch was computed. |
| Tizen | tizen40 was computed. tizen60 was computed. |
| Xamarin.iOS | xamarinios was computed. |
| Xamarin.Mac | xamarinmac was computed. |
| Xamarin.TVOS | xamarintvos was computed. |
| Xamarin.WatchOS | xamarinwatchos was computed. |
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.
-
.NETStandard 2.0
- Hand.Generators.EasySyntax (>= 0.2.0.5)
- Microsoft.CodeAnalysis.Analyzers (>= 5.3.0)
- Microsoft.CodeAnalysis.CSharp (>= 5.3.0)
NuGet packages (3)
Showing the top 3 NuGet packages that depend on Hand.GenerateCore:
| Package | Downloads |
|---|---|
|
Hand.GenerateCachedProperty
Package Description |
|
|
Hand.GenerateProperty
Package Description |
|
|
Hand.GeneratePoco
Package Description |
GitHub repositories
This package is not used by any popular GitHub repositories.