最佳实践和常见问题
本文档介绍真实应用场景、最佳实践对比和常见问题解答。
📋 文档信息
- 难度级别: 高级
- 预计阅读时间: 15 分钟
瀵规瘮琛ㄦ牸
| 鏂归潰 | 鉁?鏈€浣冲疄璺? | 鉂?鍙嶆ā寮? | 鍘熷洜 |
|---|---|---|---|
| 鏁版嵁妯″瀷 | 浣跨敤 record 绫诲瀷 | 浣跨敤鏅€?class | record 鑷姩瀹炵幇 IEquatable锛屾敮鎸佺紦瀛? |
| 闆嗗悎绫诲瀷 | 浣跨敤 ImmutableArray<T> | 浣跨敤 List<T> 鎴?Array | 涓嶅彲鍙橀泦鍚堢‘淇濈紦瀛樻纭€? |
| 璇硶杩囨护 | 鍦?predicate 涓彧鍋氳娉曟鏌? | 鍦?predicate 涓娇鐢ㄨ涔夋ā鍨? | 璇硶妫€鏌ュ揩 100 鍊嶄互涓? |
| 鏁版嵁浼犺緭 | 鍙紶杈撳繀瑕佺殑鏁版嵁 | 浼犺緭鏁翠釜璇硶鏍戞垨绗﹀彿 | 鍑忓皯鍐呭瓨鍗犵敤鍜屾瘮杈冨紑閿€ |
| 绠¢亾缁勭粐 | 浣跨敤澶氫釜灏忕閬撶粍鍚? | 浣跨敤鍗曚釜澶х閬? | 鎻愰珮鍙淮鎶ゆ€у拰缂撳瓨鏁堢巼 |
| 浠g爜鐢熸垚 | 浣跨敤 StringBuilder | 浣跨敤瀛楃涓叉嫾鎺? | StringBuilder 鎬ц兘鏇村ソ |
| 閿欒澶勭悊 | 杩斿洖 null 杩囨护鏃犳晥鏁版嵁 | 鎶涘嚭寮傚父 | 寮傚父浼氫腑鏂暣涓敓鎴愯繃绋? |
| 鍛藉悕绌洪棿 | 浣跨敤瀹屾暣鐨勫懡鍚嶇┖闂? | 浣跨敤 using 鎸囦护 | 閬垮厤鍛藉悕鍐茬獊 |
璇︾粏绀轰緥
1. 鏁版嵁妯″瀷璁捐
// 鉂?鍙嶆ā寮忥細浣跨敤鏅€氱被
public class ClassInfo
{
public string Name { get; set; }
public List<string> Properties { get; set; }
// 闇€瑕佹墜鍔ㄥ疄鐜?Equals 鍜?GetHashCode
// 瀹规槗鍑洪敊锛岄毦浠ョ淮鎶?
}
// 鉁?鏈€浣冲疄璺碉細浣跨敤 record
public record ClassInfo(
string Name,
ImmutableArray<string> Properties
);
// 鑷姩瀹炵幇 IEquatable锛屾敮鎸佺紦瀛?
// 涓嶅彲鍙橈紝绾跨▼瀹夊叏2. 璇硶杩囨护
// 鉂?鍙嶆ā寮忥細鍦?predicate 涓仛澶嶆潅妫€鏌?
var provider = context.SyntaxProvider.CreateSyntaxProvider(
predicate: (node, ct) =>
{
if (node is not ClassDeclarationSyntax cls)
return false;
// 鎱細瀛楃涓叉搷浣?
var text = cls.ToString();
if (text.Length > 10000)
return false;
// 鎱細閬嶅巻鎵€鏈夋垚鍛?
foreach (var member in cls.Members)
{
if (member is MethodDeclarationSyntax)
return true;
}
return false;
},
transform: (ctx, ct) => ctx.Node
);
// 鉁?鏈€浣冲疄璺碉細蹇€熻娉曟鏌?
var provider = context.SyntaxProvider.CreateSyntaxProvider(
predicate: (node, ct) =>
{
// 蹇細绫诲瀷妫€鏌?
if (node is not ClassDeclarationSyntax cls)
return false;
// 蹇細妫€鏌ヤ慨楗扮
if (!cls.Modifiers.Any(m => m.IsKind(SyntaxKind.PublicKeyword)))
return false;
// 蹇細妫€鏌ョ壒鎬ф暟閲?
if (cls.AttributeLists.Count == 0)
return false;
return true;
},
transform: (ctx, ct) =>
{
// 鍦ㄨ繖閲屽仛澶嶆潅妫€鏌?
var cls = (ClassDeclarationSyntax)ctx.Node;
var symbol = ctx.SemanticModel.GetDeclaredSymbol(cls);
return symbol;
}
);3. 閿欒澶勭悊
// 鉂?鍙嶆ā寮忥細鎶涘嚭寮傚父
var provider = context.SyntaxProvider.CreateSyntaxProvider(
predicate: (node, ct) => node is ClassDeclarationSyntax,
transform: (ctx, ct) =>
{
var symbol = ctx.SemanticModel.GetDeclaredSymbol(ctx.Node);
if (symbol == null)
throw new InvalidOperationException("Symbol not found"); // 浼氫腑鏂敓鎴?
return symbol;
}
);
// 鉁?鏈€浣冲疄璺碉細杩斿洖 null 骞惰繃婊?
var provider = context.SyntaxProvider.CreateSyntaxProvider(
predicate: (node, ct) => node is ClassDeclarationSyntax,
transform: (ctx, ct) =>
{
var symbol = ctx.SemanticModel.GetDeclaredSymbol(ctx.Node);
if (symbol == null)
return null; // 杩斿洖 null
return symbol;
}
)
.Where(symbol => symbol != null); // 杩囨护 null4. 浠g爜鐢熸垚
// 鉂?鍙嶆ā寮忥細瀛楃涓叉嫾鎺?
context.RegisterSourceOutput(classes, (spc, classInfo) =>
{
string source = "";
source += "namespace Generated\n";
source += "{\n";
source += " public class " + classInfo.Name + "\n";
source += " {\n";
foreach (var prop in classInfo.Properties)
{
source += " public string " + prop + " { get; set; }\n";
}
source += " }\n";
source += "}\n";
spc.AddSource($"{classInfo.Name}.g.cs", source);
});
// 鉁?鏈€浣冲疄璺碉細浣跨敤 StringBuilder
context.RegisterSourceOutput(classes, (spc, classInfo) =>
{
var sb = new StringBuilder();
sb.AppendLine("namespace Generated");
sb.AppendLine("{");
sb.AppendLine($" public class {classInfo.Name}");
sb.AppendLine(" {");
foreach (var prop in classInfo.Properties)
{
sb.AppendLine($" public string {prop} {{ get; set; }}");
}
sb.AppendLine(" }");
sb.AppendLine("}");
spc.AddSource($"{classInfo.Name}.g.cs", sb.ToString());
});5. 绠¢亾缁勭粐
// 鉂?鍙嶆ā寮忥細鍗曚釜澶х閬?
var provider = context.SyntaxProvider.CreateSyntaxProvider(
predicate: (node, ct) =>
node is ClassDeclarationSyntax ||
node is InterfaceDeclarationSyntax ||
node is StructDeclarationSyntax,
transform: (ctx, ct) =>
{
// 澶嶆潅鐨勯€昏緫澶勭悊鎵€鏈夌被鍨?
if (ctx.Node is ClassDeclarationSyntax cls)
{
// 澶勭悊绫?
}
else if (ctx.Node is InterfaceDeclarationSyntax iface)
{
// 澶勭悊鎺ュ彛
}
else if (ctx.Node is StructDeclarationSyntax str)
{
// 澶勭悊缁撴瀯
}
return null;
}
);
// 鉁?鏈€浣冲疄璺碉細澶氫釜灏忕閬?
var classes = context.SyntaxProvider.CreateSyntaxProvider(
predicate: (node, ct) => node is ClassDeclarationSyntax,
transform: (ctx, ct) => ProcessClass(ctx)
);
var interfaces = context.SyntaxProvider.CreateSyntaxProvider(
predicate: (node, ct) => node is InterfaceDeclarationSyntax,
transform: (ctx, ct) => ProcessInterface(ctx)
);
var structs = context.SyntaxProvider.CreateSyntaxProvider(
predicate: (node, ct) => node is StructDeclarationSyntax,
transform: (ctx, ct) => ProcessStruct(ctx)
);
// 鍒嗗埆澶勭悊鎴栫粍鍚?
context.RegisterSourceOutput(classes, GenerateClassCode);
context.RegisterSourceOutput(interfaces, GenerateInterfaceCode);
context.RegisterSourceOutput(structs, GenerateStructCode);甯歌闂
1. 涓轰粈涔堟垜鐨勫閲忕敓鎴愬櫒娌℃湁缂撳瓨鏁堟灉锛?
闂锛氭瘡娆$紪璇戦兘閲嶆柊鐢熸垚浠g爜锛屽嵆浣挎病鏈変换浣曞彉鍖栥€?
鍘熷洜锛?
- 鏁版嵁妯″瀷娌℃湁姝g‘瀹炵幇
IEquatable<T> - 浣跨敤浜嗗彲鍙橀泦鍚堬紙濡?
List<T>锛? - 鏁版嵁妯″瀷鍖呭惈浜嗕笉蹇呰鐨勬暟鎹紙濡傛暣涓娉曟爲锛?
瑙e喅鏂规锛?
// 鉂?闂浠g爜
public class ClassInfo
{
public string Name { get; set; }
public List<string> Properties { get; set; } // 鍙彉闆嗗悎
}
// 鉁?姝g‘浠g爜
public record ClassInfo(
string Name,
ImmutableArray<string> Properties // 涓嶅彲鍙橀泦鍚?
);2. 濡備綍璋冭瘯澧為噺鐢熸垚鍣紵
鏂规硶 1锛氫娇鐢?Debugger.Launch()
public void Initialize(IncrementalGeneratorInitializationContext context)
{
#if DEBUG
if (!Debugger.IsAttached)
{
Debugger.Launch();
}
#endif
// 鐢熸垚鍣ㄤ唬鐮?..
}*鏂规硶 2锛氫娇鐢ㄦ棩蹇?
public void Initialize(IncrementalGeneratorInitializationContext context)
{
var provider = context.SyntaxProvider.CreateSyntaxProvider(
predicate: (node, ct) =>
{
var result = node is ClassDeclarationSyntax;
// 鍐欏叆鏃ュ織鏂囦欢
File.AppendAllText("generator.log", $"Predicate: {node.GetType().Name} -> {result}\n");
return result;
},
transform: (ctx, ct) =>
{
var cls = (ClassDeclarationSyntax)ctx.Node;
File.AppendAllText("generator.log", $"Transform: {cls.Identifier.Text}\n");
return cls;
}
);
}3. 澧為噺鐢熸垚鍣ㄦ瘮浼犵粺鐢熸垚鍣ㄦ參鎬庝箞鍔烇紵
鍘熷洜锛?
predicate涓仛浜嗗お澶氬伐浣?- 鏁版嵁妯″瀷澶鏉傦紝姣旇緝寮€閿€澶?
- 娌℃湁姝g‘浣跨敤缂撳瓨
浼樺寲姝ラ锛?
- 绠€鍖?predicate锛氬彧鍋氭渶鍩烘湰鐨勮娉曟鏌?
- 鏈€灏忓寲鏁版嵁锛氬彧浼犺緭蹇呰鐨勪俊鎭?
- 浣跨敤 record锛氳嚜鍔ㄥ疄鐜伴珮鏁堢殑鐩哥瓑姣旇緝
- 娴嬮噺鎬ц兘锛氫娇鐢?
Stopwatch娴嬮噺鍚勪釜闃舵鐨勮€楁椂
var provider = context.SyntaxProvider.CreateSyntaxProvider(
predicate: (node, ct) =>
{
var sw = Stopwatch.StartNew();
var result = node is ClassDeclarationSyntax;
sw.Stop();
if (sw.ElapsedMilliseconds > 1)
{
// 璁板綍鎱㈢殑鎿嶄綔
File.AppendAllText("perf.log",
$"Slow predicate: {sw.ElapsedMilliseconds}ms\n");
}
return result;
},
transform: (ctx, ct) => { /* ... */ }
);4. 濡備綍澶勭悊澶氫釜鏂囦欢鐨勪緷璧栧叧绯伙紵
鍦烘櫙锛氱敓鎴愮殑浠g爜渚濊禆浜庡涓簮鏂囦欢銆?
瑙e喅鏂规锛氫娇鐢?Combine 缁勫悎澶氫釜绠¢亾銆?
public void Initialize(IncrementalGeneratorInitializationContext context)
{
// 绠¢亾 1锛氭煡鎵炬墍鏈夊疄浣撶被
var entities = context.SyntaxProvider.CreateSyntaxProvider(
predicate: (node, ct) => node is ClassDeclarationSyntax,
transform: (ctx, ct) => GetEntityInfo(ctx)
).Where(info => info != null);
// 绠¢亾 2锛氭煡鎵炬墍鏈夐厤缃被
var configs = context.SyntaxProvider.CreateSyntaxProvider(
predicate: (node, ct) => node is ClassDeclarationSyntax,
transform: (ctx, ct) => GetConfigInfo(ctx)
).Where(info => info != null);
// 缁勫悎涓や釜绠¢亾
var combined = entities.Collect().Combine(configs.Collect());
// 浣跨敤缁勫悎鐨勬暟鎹敓鎴愪唬鐮?
context.RegisterSourceOutput(combined, (spc, data) =>
{
var (entityList, configList) = data;
// 鏍规嵁瀹炰綋鍜岄厤缃敓鎴愪唬鐮?
var source = GenerateCode(entityList, configList);
spc.AddSource("Generated.g.cs", source);
});
}5. 鐢熸垚鐨勪唬鐮佹湁缂栬瘧閿欒鎬庝箞鍔烇紵
璋冭瘯姝ラ锛?
- **鏌ョ湅鐢熸垚鐨勬枃浠?*锛氬湪
obj/Debug/netX.X/generated/鐩綍涓? - 娣诲姞璇婃柇锛氭姤鍛婄敓鎴愯繃绋嬩腑鐨勯棶棰?
- 楠岃瘉璇硶锛氫娇鐢?Roslyn API 瑙f瀽鐢熸垚鐨勪唬鐮?
context.RegisterSourceOutput(classes, (spc, classInfo) =>
{
try
{
var source = GenerateCode(classInfo);
// 楠岃瘉鐢熸垚鐨勪唬鐮佹槸鍚︽湁璇硶閿欒
var tree = CSharpSyntaxTree.ParseText(source);
var diagnostics = tree.GetDiagnostics();
if (diagnostics.Any(d => d.Severity == DiagnosticSeverity.Error))
{
// 鎶ュ憡閿欒
foreach (var diagnostic in diagnostics)
{
spc.ReportDiagnostic(Diagnostic.Create(
new DiagnosticDescriptor(
"SG0001",
"Generated code has syntax error",
diagnostic.GetMessage(),
"SourceGenerator",
DiagnosticSeverity.Error,
true
),
Location.None
));
}
return; // 涓嶆坊鍔犳湁閿欒鐨勪唬鐮?
}
spc.AddSource($"{classInfo.Name}.g.cs", source);
}
catch (Exception ex)
{
// 鎶ュ憡寮傚父
spc.ReportDiagnostic(Diagnostic.Create(
new DiagnosticDescriptor(
"SG0002",
"Code generation failed",
$"Failed to generate code for {classInfo.Name}: {ex.Message}",
"SourceGenerator",
DiagnosticSeverity.Error,
true
),
Location.None
));
}
});6. 濡備綍鍦ㄥ閲忕敓鎴愬櫒涓闂」鐩厤缃紵
鍦烘櫙锛氶渶瑕佹牴鎹」鐩厤缃紙濡?MSBuild 灞炴€э級鐢熸垚涓嶅悓鐨勪唬鐮併€?
瑙e喅鏂规锛氫娇鐢?AnalyzerConfigOptionsProvider銆?
public void Initialize(IncrementalGeneratorInitializationContext context)
{
// 鑾峰彇鍒嗘瀽鍣ㄩ厤缃?
var configProvider = context.AnalyzerConfigOptionsProvider;
// 鍒涘缓绠¢亾
var classes = context.SyntaxProvider.CreateSyntaxProvider(
predicate: (node, ct) => node is ClassDeclarationSyntax,
transform: (ctx, ct) => ctx.Node
);
// 缁勫悎閰嶇疆鍜岀被
var combined = classes.Combine(configProvider);
context.RegisterSourceOutput(combined, (spc, data) =>
{
var (classDecl, configProvider) = data;
// 璇诲彇閰嶇疆
configProvider.GlobalOptions.TryGetValue(
"build_property.GenerateDebugCode",
out var generateDebug
);
var includeDebug = generateDebug == "true";
// 鏍规嵁閰嶇疆鐢熸垚浠g爜
var source = GenerateCode(classDecl, includeDebug);
spc.AddSource("Generated.g.cs", source);
});
}鍦ㄩ」鐩枃浠朵腑璁剧疆锛?
<PropertyGroup>
<GenerateDebugCode>true</GenerateDebugCode>
</PropertyGroup>7. 澧為噺鐢熸垚鍣ㄥ彲浠ョ敓鎴愬灏戜釜鏂囦欢锛?
闄愬埗锛氱悊璁轰笂娌℃湁闄愬埗锛屼絾寤鸿锛?
- 姣忎釜绫荤敓鎴愪竴涓枃浠讹細閫傚悎灏忓瀷椤圭洰
- 澶氫釜绫荤敓鎴愪竴涓枃浠讹細閫傚悎澶у瀷椤圭洰锛堝噺灏戞枃浠舵暟閲忥級
鎺ㄨ崘鍋氭硶锛?
// 鏂规 1锛氭瘡涓被涓€涓枃浠讹紙灏忓瀷椤圭洰锛?
context.RegisterSourceOutput(classes, (spc, classInfo) =>
{
var source = GenerateCode(classInfo);
spc.AddSource($"{classInfo.Name}.g.cs", source);
});
// 鏂规 2锛氭墍鏈夌被涓€涓枃浠讹紙澶у瀷椤圭洰锛?
var allClasses = classes.Collect();
context.RegisterSourceOutput(allClasses, (spc, classList) =>
{
var sb = new StringBuilder();
foreach (var classInfo in classList)
{
sb.AppendLine(GenerateCode(classInfo));
}
spc.AddSource("AllGenerated.g.cs", sb.ToString());
});
// 鏂规 3锛氭寜鍛藉悕绌洪棿鍒嗙粍锛堟帹鑽愶級
var groupedByNamespace = classes
.Collect()
.Select((classList, ct) =>
classList.GroupBy(c => c.Namespace).ToImmutableArray()
);
context.RegisterSourceOutput(groupedByNamespace, (spc, groups) =>
{
foreach (var group in groups)
{
var sb = new StringBuilder();
sb.AppendLine($"namespace {group.Key}");
sb.AppendLine("{");
foreach (var classInfo in group)
{
sb.AppendLine(GenerateCode(classInfo));
}
sb.AppendLine("}");
spc.AddSource($"{group.Key}.g.cs", sb.ToString());
}
});8. 濡備綍娴嬭瘯澧為噺鐢熸垚鍣紵
鎺ㄨ崘鏂规硶锛氫娇鐢?Microsoft.CodeAnalysis.CSharp.SourceGenerators.Testing銆?
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Testing;
using Microsoft.CodeAnalysis.Testing;
using Microsoft.CodeAnalysis.Testing.Verifiers;
using Xunit;
public class IncrementalGeneratorTests
{
[Fact]
public async Task GeneratesBuilderClass()
{
var source = @"
using System;
namespace TestNamespace
{
[GenerateBuilder]
public partial class Person
{
public string Name { get; set; }
public int Age { get; set; }
}
}";
var expected = @"
namespace TestNamespace
{
public class PersonBuilder
{
private string _name;
private int _age;
public PersonBuilder WithName(string value)
{
_name = value;
return this;
}
public PersonBuilder WithAge(int value)
{
_age = value;
return this;
}
public Person Build()
{
return new Person
{
Name = _name,
Age = _age
};
}
}
}";
await new CSharpSourceGeneratorTest<BuilderGenerator, XUnitVerifier>
{
TestState =
{
Sources = { source },
GeneratedSources =
{
(typeof(BuilderGenerator), "PersonBuilder.g.cs", expected)
}
}
}.RunAsync();
}
}馃敆 鐩稿叧璧勬簮
娣卞叆瀛︿範
- [蹇€熷紑濮媇(../guide/getting-started.md) - 寮€濮嬩娇鐢ㄦ簮鐢熸垚鍣?
- Hello World 绀轰緥 - 鏈€绠€鍗曠殑鍏ラ棬绀轰緥
- [ToString 鐢熸垚鍣╙(./tostring-generator.md) - 瀹炵敤鐨勪唬鐮佺敓鎴愮ず渚?
- [Builder 鐢熸垚鍣╙(./builder-generator.md) - 澶嶆潅鐨勪唬鐮佺敓鎴愭ā寮?
- 娴嬭瘯绀轰緥 - 浜嗚В濡備綍娴嬭瘯婧愮敓鎴愬櫒
API 鍙傝€?
- 澧為噺绠¢亾 API - 澧為噺鐢熸垚鍣?API 鍙傝€?
- [鏈€浣冲疄璺礭(../api/best-practices.md) - 婧愮敓鎴愬櫒寮€鍙戞渶浣冲疄璺?
- 楂樼骇妯″紡 - 楂樼骇鎶€宸у拰妯″紡
瀹樻柟鏂囨。
- Incremental Generators - Roslyn 瀹樻柟鏂囨。
- Source Generators Cookbook - 婧愮敓鎴愬櫒鎸囧崡
- IIncrementalGenerator API - API 鍙傝€?
鐩稿叧鏂囨。
- 澧為噺绠¢亾 API 璇﹁В - 娣卞叆浜嗚В绠¢亾鎿嶄綔
- [鎬ц兘浼樺寲鏈€浣冲疄璺礭(/api/best-practices) - 鎬ц兘浼樺寲鎶€宸?
- 婧愮敓鎴愬櫒娴嬭瘯 - 娴嬭瘯鍜岃皟璇曟妧鏈?
- 璇箟妯″瀷 API - 璇箟鍒嗘瀽璇﹁В
绀轰緥椤圭洰
- [ToString 鐢熸垚鍣╙(/examples/tostring-generator) - 瀹炵敤鐨勪唬鐮佺敓鎴愮ず渚?
- [Builder 鐢熸垚鍣╙(/examples/builder-generator) - 澶嶆潅鐨勪唬鐮佺敓鎴愭ā寮?
- 璇婃柇鎶ュ憡 - 閿欒鎶ュ憡鎶€鏈?
绀惧尯璧勬簮
- Source Generators Samples - 瀹樻柟绀轰緥
- Awesome Source Generators - 绀惧尯璧勬簮鍒楄〃
- Source Generator Playground - 鍦ㄧ嚎娴嬭瘯宸ュ叿
鎬ц兘鍒嗘瀽宸ュ叿
- BenchmarkDotNet - 鎬ц兘鍩哄噯娴嬭瘯
- PerfView - 鎬ц兘鍒嗘瀽宸ュ叿
- dotnet-trace - 璺熻釜宸ュ叿
涓嬩竴姝ュ涔?
鍩虹宸╁浐锛?
- 澶嶄範 Roslyn 鍩虹
- 鐞嗚В 缂栬瘧娴佺▼
- 鎺屾彙 [璇硶鏍慮(/guide/syntax-tree)
杩涢樁瀛︿範锛?
- 瀛︿範 [ToString 鐢熸垚鍣╙(/examples/tostring-generator)
- 瀹炶返 [Builder 鐢熸垚鍣╙(/examples/builder-generator)
- 鎺屾彙 [娴嬭瘯鎶€鏈痌(/examples/testing)
**娣卞叆鐮旂┒**锛?
- 鐮旂┒ 澧為噺绠¢亾 API
- 瀛︿範 楂樼骇妯″紡
- 鎺屾彙 鎬ц兘浼樺寲
鎬荤粨
澧為噺鐢熸垚鍣ㄦ槸 Roslyn 婧愮敓鎴愬櫒鐨勯噸瑕佽繘鍖栵紝閫氳繃鏅鸿兘缂撳瓨鏈哄埗鏄捐憲鎻愰珮浜嗙紪璇戞€ц兘銆傚叧閿鐐癸細
- 浣跨敤 record 绫诲瀷锛氳嚜鍔ㄥ疄鐜?IEquatable锛屾敮鎸佺紦瀛?
- **蹇€熻娉曡繃婊?*锛氬湪 predicate 涓彧鍋氳娉曟鏌?
- 鏈€灏忓寲鏁版嵁浼犺緭锛氬彧浼犺緭蹇呰鐨勪俊鎭?
- **姝g‘鐨勭閬撶粍缁?*锛氫娇鐢ㄥ涓皬绠¢亾缁勫悎
- 鎬ц兘娴嬭瘯锛氭寔缁祴閲忓拰浼樺寲鎬ц兘
閫氳繃閬靛惊鏈€浣冲疄璺碉紝浣犲彲浠ュ垱寤洪珮鏁堛€佸彲缁存姢鐨勫閲忕敓鎴愬櫒锛屼负椤圭洰甯︽潵鏄捐憲鐨勬€ц兘鎻愬崌銆?
鏂囨。瀛楁暟缁熻锛氱害 8,500 瀛?
4. 濡備綍鍦ㄥ閲忕敓鎴愬櫒涓鐞嗗涓緭鍏ユ簮锛?
闂锛氶渶瑕佸悓鏃跺鐞嗗涓壒鎬ф垨澶氱绫诲瀷鐨勮緭鍏ャ€?
瑙e喅鏂规锛氫娇鐢?Combine 缁勫悎澶氫釜鎻愪緵鍣?
public void Initialize(IncrementalGeneratorInitializationContext context)
{
// 鏀堕泦绫讳俊鎭?
var classes = context.SyntaxProvider
.ForAttributeWithMetadataName(
"GenerateAttribute",
predicate: (node, _) => node is ClassDeclarationSyntax,
transform: (ctx, _) => GetClassInfo(ctx));
// 鏀堕泦鎺ュ彛淇℃伅
var interfaces = context.SyntaxProvider
.ForAttributeWithMetadataName(
"GenerateAttribute",
predicate: (node, _) => node is InterfaceDeclarationSyntax,
transform: (ctx, _) => GetInterfaceInfo(ctx));
// 缁勫悎涓や釜鎻愪緵鍣?
var combined = classes.Collect().Combine(interfaces.Collect());
context.RegisterSourceOutput(combined, (spc, data) =>
{
var (classInfos, interfaceInfos) = data;
// 鍚屾椂澶勭悊绫诲拰鎺ュ彛
foreach (var classInfo in classInfos)
{
GenerateClassCode(spc, classInfo);
}
foreach (var interfaceInfo in interfaceInfos)
{
GenerateInterfaceCode(spc, interfaceInfo);
}
});
}5. 濡備綍娴嬭瘯澧為噺鐢熸垚鍣ㄧ殑缂撳瓨琛屼负锛?
闂锛氬浣曢獙璇佸閲忕敓鎴愬櫒纭疄浣跨敤浜嗙紦瀛橈紵
瑙e喅鏂规锛氫娇鐢?GeneratorDriver 鐨?RunGeneratorsAndUpdateCompilation 鏂规硶
[Fact]
public void IncrementalGenerator_UsesCaching()
{
var source = @"
[Generate]
public partial class MyClass
{
public string Name { get; set; }
}";
var compilation = CreateCompilation(source);
var generator = new MyIncrementalGenerator();
// 绗竴娆¤繍琛?
var driver1 = CSharpGeneratorDriver.Create(generator);
driver1 = driver1.RunGeneratorsAndUpdateCompilation(
compilation,
out var outputCompilation1,
out var diagnostics1);
// 绗簩娆¤繍琛岋紙娌℃湁鏀瑰彉锛?
var driver2 = driver1.RunGeneratorsAndUpdateCompilation(
outputCompilation1,
out var outputCompilation2,
out var diagnostics2);
// 楠岃瘉缁撴灉鐩稿悓锛堜娇鐢ㄤ簡缂撳瓨锛?
var result1 = driver1.GetRunResult();
var result2 = driver2.GetRunResult();
Assert.Equal(
result1.GeneratedTrees.Length,
result2.GeneratedTrees.Length);
}鏈€鍚庢洿鏂? 2025-01-21
Q2: 澧為噺鐢熸垚鍣ㄥ浣曞鐞嗘枃浠跺垹闄わ紵
A: 澧為噺鐢熸垚鍣ㄤ細鑷姩澶勭悊鏂囦欢鍒犻櫎锛?
public void Initialize(IncrementalGeneratorInitializationContext context)
{
var classData = context.SyntaxProvider
.ForAttributeWithMetadataName(
"GenerateAttribute",
predicate: (node, _) => node is ClassDeclarationSyntax,
transform: (ctx, _) => GetClassInfo(ctx));
// 褰撴枃浠惰鍒犻櫎鏃讹紝瀵瑰簲鐨勬暟鎹細鑷姩浠庣閬撲腑绉婚櫎
// 涓嶉渶瑕佹墜鍔ㄥ鐞嗗垹闄ら€昏緫
context.RegisterSourceOutput(classData, (spc, data) =>
{
// 鍙负瀛樺湪鐨勭被鐢熸垚浠g爜
var code = GenerateCode(data);
spc.AddSource($"{data.ClassName}.g.cs", code);
});
}Q3: 濡備綍璋冭瘯澧為噺鐢熸垚鍣ㄧ殑缂撳瓨琛屼负锛?
A: 浣跨敤鏃ュ織鍜岃瘖鏂伐鍏凤細
public void Initialize(IncrementalGeneratorInitializationContext context)
{
var classData = context.SyntaxProvider
.ForAttributeWithMetadataName(
"GenerateAttribute",
predicate: (node, _) => node is ClassDeclarationSyntax,
transform: (ctx, _) =>
{
var data = GetClassInfo(ctx);
// 娣诲姞鏃ュ織
System.Diagnostics.Debug.WriteLine(
$"Transform called for: {data.ClassName}");
return data;
});
context.RegisterSourceOutput(classData, (spc, data) =>
{
System.Diagnostics.Debug.WriteLine(
$"Generate called for: {data.ClassName}");
var code = GenerateCode(data);
spc.AddSource($"{data.ClassName}.g.cs", code);
});
}鏈€鍚庢洿鏂? 2025-01-21
下一步
最后更新: 2025-01-21