高级管道操作
掌握复杂的管道模式和高级技巧
📋 文档信息
| 属性 | 值 |
|---|---|
| 难度 | 高级 |
| 阅读时间 | 40 分钟 |
| 前置知识 | 管道操作、数据流转换、缓存机制 |
| 相关文档 | 管道操作详解 |
🎯 学习目标
完成本文档后,你将能够:
- ✅ 使用 WithComparer 自定义缓存行为
- ✅ 使用 WithTrackingName 进行性能分析
- ✅ 使用 ForAttributeWithMetadataName 高效过滤
- ✅ 实现多源组合模式
- ✅ 实现分组聚合模式
- ✅ 实现条件管道模式
📚 快速导航
| 章节 | 说明 |
|---|---|
| WithComparer | 自定义比较器 |
| WithTrackingName | 性能跟踪 |
| ForAttributeWithMetadataName | 高效特性过滤 |
| 多源组合 | 组合多个数据源 |
| 分组聚合 | 按条件分组 |
| 条件管道 | 条件分支 |
WithComparer
自定义比较器
使用自定义比较器来控制缓存行为:
csharp
using Microsoft.CodeAnalysis;
using System.Collections.Generic;
/// <summary>
/// 使用 WithComparer 自定义缓存行为
/// </summary>
public class WithComparerDemo
{
/// <summary>
/// 类信息
/// </summary>
public class ClassInfo
{
public string Name { get; set; }
public string Namespace { get; set; }
public List<string> Properties { get; set; }
}
/// <summary>
/// 自定义比较器:只比较类名
/// </summary>
public class ClassInfoComparer : IEqualityComparer<ClassInfo>
{
public bool Equals(ClassInfo x, ClassInfo y)
{
if (x == null && y == null) return true;
if (x == null || y == null) return false;
// 只比较类名,忽略其他属性
return x.Name == y.Name;
}
public int GetHashCode(ClassInfo obj)
{
return obj?.Name?.GetHashCode() ?? 0;
}
}
public void Initialize(IncrementalGeneratorInitializationContext context)
{
var classInfos = context.SyntaxProvider
.CreateSyntaxProvider(
predicate: (node, _) => node is ClassDeclarationSyntax,
transform: (ctx, _) =>
{
var classDecl = (ClassDeclarationSyntax)ctx.Node;
var symbol = ctx.SemanticModel.GetDeclaredSymbol(classDecl);
return new ClassInfo
{
Name = symbol.Name,
Namespace = symbol.ContainingNamespace.ToDisplayString(),
Properties = symbol.GetMembers()
.OfType<IPropertySymbol>()
.Select(p => p.Name)
.ToList()
};
})
.WithComparer(new ClassInfoComparer()); // 使用自定义比较器
context.RegisterSourceOutput(classInfos, (spc, info) =>
{
var code = GenerateCode(info);
spc.AddSource($"{info.Name}.g.cs", code);
});
}
private string GenerateCode(ClassInfo info)
{
return $@"
// Generated for class: {info.Name}
namespace {info.Namespace}
{{
partial class {info.Name}
{{
// Generated code
}}
}}";
}
}WithTrackingName
性能跟踪
为管道步骤添加跟踪名称,便于性能分析和调试:
csharp
using Microsoft.CodeAnalysis;
/// <summary>
/// 使用 WithTrackingName 进行性能分析
/// </summary>
public class WithTrackingNameDemo
{
public void Initialize(IncrementalGeneratorInitializationContext context)
{
// 为每个管道步骤添加跟踪名称
var classes = context.SyntaxProvider
.CreateSyntaxProvider(
predicate: (node, _) => node is ClassDeclarationSyntax,
transform: (ctx, _) => (ClassDeclarationSyntax)ctx.Node)
.WithTrackingName("FindClasses"); // 跟踪名称
var publicClasses = classes
.Where((classDecl, _) =>
classDecl.Modifiers.Any(m => m.IsKind(SyntaxKind.PublicKeyword)))
.WithTrackingName("FilterPublicClasses"); // 跟踪名称
var classNames = publicClasses
.Select((classDecl, _) => classDecl.Identifier.Text)
.WithTrackingName("ExtractClassNames"); // 跟踪名称
context.RegisterSourceOutput(classNames, (spc, name) =>
{
var code = $"// Class: {name}";
spc.AddSource($"{name}.g.cs", code);
});
}
}使用场景:
- 性能分析:识别慢的管道步骤
- 调试:了解数据流经哪些步骤
- 日志记录:记录管道执行情况
ForAttributeWithMetadataName
高效特性过滤
这是最高效的过滤方式,专门用于查找带有特定特性的符号:
csharp
using Microsoft.CodeAnalysis;
using System.Collections.Immutable;
/// <summary>
/// 使用 ForAttributeWithMetadataName 高效过滤
/// </summary>
[Generator]
public class ForAttributeDemo : IIncrementalGenerator
{
public void Initialize(IncrementalGeneratorInitializationContext context)
{
// 查找所有带 [GenerateToString] 特性的类
var classesWithAttribute = context.SyntaxProvider
.ForAttributeWithMetadataName(
fullyQualifiedMetadataName: "MyNamespace.GenerateToStringAttribute",
predicate: (node, _) => node is ClassDeclarationSyntax,
transform: (ctx, _) => GetClassInfo(ctx))
.Where(info => info != null);
context.RegisterSourceOutput(classesWithAttribute, (spc, info) =>
{
var code = GenerateToStringMethod(info);
spc.AddSource($"{info.ClassName}.ToString.g.cs", code);
});
}
/// <summary>
/// 从语法上下文提取类信息
/// </summary>
private ClassInfo GetClassInfo(GeneratorAttributeSyntaxContext context)
{
// context.TargetSymbol 是带特性的符号
var classSymbol = (INamedTypeSymbol)context.TargetSymbol;
// context.TargetNode 是语法节点
var classDecl = (ClassDeclarationSyntax)context.TargetNode;
// context.Attributes 是特性列表
var attribute = context.Attributes[0];
// 提取特性参数
var includeFields = false;
if (attribute.ConstructorArguments.Length > 0)
{
includeFields = (bool)attribute.ConstructorArguments[0].Value;
}
// 获取所有属性
var properties = classSymbol.GetMembers()
.OfType<IPropertySymbol>()
.Where(p => p.DeclaredAccessibility == Accessibility.Public)
.Select(p => p.Name)
.ToImmutableArray();
// 获取所有字段(如果需要)
var fields = includeFields
? classSymbol.GetMembers()
.OfType<IFieldSymbol>()
.Where(f => f.DeclaredAccessibility == Accessibility.Public)
.Select(f => f.Name)
.ToImmutableArray()
: ImmutableArray<string>.Empty;
return new ClassInfo(
classSymbol.Name,
classSymbol.ContainingNamespace.ToDisplayString(),
properties,
fields);
}
private string GenerateToStringMethod(ClassInfo info)
{
var members = info.Properties.Concat(info.Fields);
var memberStrings = string.Join(", ",
members.Select(m => $"{m} = {{{m}}}"));
return $@"
namespace {info.Namespace}
{{
partial class {info.ClassName}
{{
public override string ToString()
{{
return $""{info.ClassName} {{ {memberStrings} }}"";
}}
}}
}}";
}
private record ClassInfo(
string ClassName,
string Namespace,
ImmutableArray<string> Properties,
ImmutableArray<string> Fields);
}ForAttributeWithMetadataName 的优势:
- 性能最优:编译器级别的优化
- 自动缓存:只在特性改变时重新计算
- 类型安全:直接获取符号信息
- 简洁代码:一步完成过滤和转换
多源组合模式
组合多个数据源
组合编译选项、类声明和配置文件:
csharp
using Microsoft.CodeAnalysis;
using System.Collections.Immutable;
/// <summary>
/// 多源组合模式
/// </summary>
[Generator]
public class MultiSourceGenerator : IIncrementalGenerator
{
public void Initialize(IncrementalGeneratorInitializationContext context)
{
// 数据源 1: 编译选项
var compilationOptions = context.CompilationProvider
.Select((comp, _) => new CompilationInfo(
comp.AssemblyName,
comp.Options.OutputKind));
// 数据源 2: 类声明
var classes = context.SyntaxProvider
.ForAttributeWithMetadataName(
"MyNamespace.GenerateAttribute",
predicate: (node, _) => node is ClassDeclarationSyntax,
transform: (ctx, _) => GetClassInfo(ctx));
// 数据源 3: 配置文件
var configFiles = context.AdditionalTextsProvider
.Where(file => file.Path.EndsWith(".config.json"))
.Select((file, ct) => ParseConfig(file, ct))
.Collect();
// 组合所有数据源
var combined = classes
.Combine(compilationOptions)
.Combine(configFiles);
// 使用组合的数据生成代码
context.RegisterSourceOutput(combined, (spc, data) =>
{
var ((classInfo, compInfo), configs) = data;
var code = GenerateCode(classInfo, compInfo, configs);
spc.AddSource($"{classInfo.Name}.g.cs", code);
});
}
private ClassInfo GetClassInfo(GeneratorAttributeSyntaxContext context)
{
var symbol = (INamedTypeSymbol)context.TargetSymbol;
return new ClassInfo(
symbol.Name,
symbol.ContainingNamespace.ToDisplayString());
}
private ConfigData ParseConfig(AdditionalText file, CancellationToken ct)
{
var content = file.GetText(ct)?.ToString() ?? "";
return new ConfigData(file.Path, content);
}
private string GenerateCode(
ClassInfo classInfo,
CompilationInfo compInfo,
ImmutableArray<ConfigData> configs)
{
return $@"
// Generated for: {classInfo.Name}
// Assembly: {compInfo.AssemblyName}
// Output: {compInfo.OutputKind}
// Configs: {configs.Length}
namespace {classInfo.Namespace}
{{
partial class {classInfo.Name}
{{
public static string AssemblyName => ""{compInfo.AssemblyName}"";
public static int ConfigCount => {configs.Length};
}}
}}";
}
private record ClassInfo(string Name, string Namespace);
private record CompilationInfo(string AssemblyName, OutputKind OutputKind);
private record ConfigData(string Path, string Content);
}分组聚合模式
按命名空间分组
将数据分组并聚合处理:
csharp
using Microsoft.CodeAnalysis;
using System.Collections.Immutable;
using System.Linq;
/// <summary>
/// 分组聚合模式
/// </summary>
[Generator]
public class GroupingGenerator : IIncrementalGenerator
{
public void Initialize(IncrementalGeneratorInitializationContext context)
{
// 获取所有类
var classes = context.SyntaxProvider
.ForAttributeWithMetadataName(
"MyNamespace.GenerateAttribute",
predicate: (node, _) => node is ClassDeclarationSyntax,
transform: (ctx, _) =>
{
var symbol = (INamedTypeSymbol)ctx.TargetSymbol;
return new ClassInfo(
symbol.Name,
symbol.ContainingNamespace.ToDisplayString());
});
// 收集所有类
var allClasses = classes.Collect();
// 按命名空间分组
var groupedByNamespace = allClasses
.Select((classes, _) =>
{
return classes
.GroupBy(c => c.Namespace)
.Select(g => new NamespaceGroup(
g.Key,
g.Select(c => c.Name).ToImmutableArray()))
.ToImmutableArray();
});
// 为每个命名空间生成代码
context.RegisterSourceOutput(groupedByNamespace, (spc, groups) =>
{
foreach (var group in groups)
{
var code = GenerateNamespaceCode(group);
var fileName = group.Namespace.Replace(".", "_");
spc.AddSource($"{fileName}.Registry.g.cs", code);
}
});
}
private string GenerateNamespaceCode(NamespaceGroup group)
{
var classNames = string.Join(", ",
group.ClassNames.Select(n => $"\"{n}\""));
return $@"
namespace {group.Namespace}
{{
/// <summary>
/// 自动生成的类注册表
/// </summary>
public static class GeneratedClassRegistry
{{
public static readonly string[] ClassNames = new[]
{{
{classNames}
}};
public static int Count => {group.ClassNames.Length};
}}
}}";
}
private record ClassInfo(string Name, string Namespace);
private record NamespaceGroup(
string Namespace,
ImmutableArray<string> ClassNames);
}条件管道模式
根据条件选择不同路径
根据编译配置选择不同的代码生成策略:
csharp
using Microsoft.CodeAnalysis;
/// <summary>
/// 条件管道模式
/// </summary>
[Generator]
public class ConditionalPipelineGenerator : IIncrementalGenerator
{
public void Initialize(IncrementalGeneratorInitializationContext context)
{
// 获取编译配置
var isDebugBuild = context.CompilationProvider
.Select((comp, _) =>
{
// 检查是否是 Debug 构建
return comp.Options.OptimizationLevel == OptimizationLevel.Debug;
});
// 获取类声明
var classes = context.SyntaxProvider
.ForAttributeWithMetadataName(
"MyNamespace.GenerateAttribute",
predicate: (node, _) => node is ClassDeclarationSyntax,
transform: (ctx, _) => (INamedTypeSymbol)ctx.TargetSymbol);
// 组合配置和类
var combined = classes.Combine(isDebugBuild);
// 根据配置选择不同的生成策略
context.RegisterSourceOutput(combined, (spc, data) =>
{
var (classSymbol, isDebug) = data;
string code;
if (isDebug)
{
// Debug 模式:生成详细的调试代码
code = GenerateDebugCode(classSymbol);
}
else
{
// Release 模式:生成优化的代码
code = GenerateOptimizedCode(classSymbol);
}
spc.AddSource($"{classSymbol.Name}.g.cs", code);
});
}
private string GenerateDebugCode(INamedTypeSymbol symbol)
{
return $@"
namespace {symbol.ContainingNamespace.ToDisplayString()}
{{
partial class {symbol.Name}
{{
// Debug 模式:包含详细日志
private static void Log(string message)
{{
System.Diagnostics.Debug.WriteLine(
$""[{symbol.Name}] {{message}}"");
}}
partial void OnCreated()
{{
Log(""Instance created"");
}}
}}
}}";
}
private string GenerateOptimizedCode(INamedTypeSymbol symbol)
{
return $@"
namespace {symbol.ContainingNamespace.ToDisplayString()}
{{
partial class {symbol.Name}
{{
// Release 模式:无日志,优化性能
[System.Runtime.CompilerServices.MethodImpl(
System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
partial void OnCreated() {{ }}
}}
}}";
}
}🔑 关键要点
高级模式总结
- WithComparer: 自定义缓存行为
- WithTrackingName: 性能分析和调试
- ForAttributeWithMetadataName: 最高效的特性过滤
- 多源组合: 组合多个数据源
- 分组聚合: 按条件分组处理
- 条件管道: 根据条件选择不同路径
使用场景
| 模式 | 使用场景 |
|---|---|
| WithComparer | 需要自定义相等性比较 |
| WithTrackingName | 性能分析和调试 |
| ForAttributeWithMetadataName | 查找带特性的类型 |
| 多源组合 | 需要多个数据源 |
| 分组聚合 | 需要按条件分组 |
| 条件管道 | 需要条件分支 |
🔗 相关资源
🚀 下一步
最后更新: 2026-02-05