Skip to content

最佳实践和常见问题

本文档介绍真实应用场景、最佳实践对比和常见问题解答。

📋 文档信息

  • 难度级别: 高级
  • 预计阅读时间: 15 分钟

瀵规瘮琛ㄦ牸

鏂归潰鉁?鏈€浣冲疄璺?鉂?鍙嶆ā寮?鍘熷洜
鏁版嵁妯″瀷浣跨敤 record 绫诲瀷浣跨敤鏅€?classrecord 鑷姩瀹炵幇 IEquatable锛屾敮鎸佺紦瀛?
闆嗗悎绫诲瀷浣跨敤 ImmutableArray<T>浣跨敤 List<T> 鎴?Array涓嶅彲鍙橀泦鍚堢‘淇濈紦瀛樻纭€?
璇硶杩囨护鍦?predicate 涓彧鍋氳娉曟鏌?鍦?predicate 涓娇鐢ㄨ涔夋ā鍨?璇硶妫€鏌ュ揩 100 鍊嶄互涓?
鏁版嵁浼犺緭鍙紶杈撳繀瑕佺殑鏁版嵁浼犺緭鏁翠釜璇硶鏍戞垨绗﹀彿鍑忓皯鍐呭瓨鍗犵敤鍜屾瘮杈冨紑閿€
绠¢亾缁勭粐浣跨敤澶氫釜灏忕閬撶粍鍚?浣跨敤鍗曚釜澶х閬?鎻愰珮鍙淮鎶ゆ€у拰缂撳瓨鏁堢巼
浠g爜鐢熸垚浣跨敤 StringBuilder浣跨敤瀛楃涓叉嫾鎺?StringBuilder 鎬ц兘鏇村ソ
閿欒澶勭悊杩斿洖 null 杩囨护鏃犳晥鏁版嵁鎶涘嚭寮傚父寮傚父浼氫腑鏂暣涓敓鎴愯繃绋?
鍛藉悕绌洪棿浣跨敤瀹屾暣鐨勫懡鍚嶇┖闂?浣跨敤 using 鎸囦护閬垮厤鍛藉悕鍐茬獊

璇︾粏绀轰緥

1. 鏁版嵁妯″瀷璁捐

csharp
// 鉂?鍙嶆ā寮忥細浣跨敤鏅€氱被
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. 璇硶杩囨护

csharp
// 鉂?鍙嶆ā寮忥細鍦?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. 閿欒澶勭悊

csharp
// 鉂?鍙嶆ā寮忥細鎶涘嚭寮傚父
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);  // 杩囨护 null

4. 浠g爜鐢熸垚

csharp
// 鉂?鍙嶆ā寮忥細瀛楃涓叉嫾鎺?
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. 绠¢亾缁勭粐

csharp
// 鉂?鍙嶆ā寮忥細鍗曚釜澶х閬?
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喅鏂规锛?

csharp
// 鉂?闂浠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()

csharp
public void Initialize(IncrementalGeneratorInitializationContext context)
{
    #if DEBUG
    if (!Debugger.IsAttached)
    {
        Debugger.Launch();
    }
    #endif
    
    // 鐢熸垚鍣ㄤ唬鐮?..
}

*鏂规硶 2锛氫娇鐢ㄦ棩蹇?

csharp
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‘浣跨敤缂撳瓨

浼樺寲姝ラ锛?

  1. 绠€鍖?predicate锛氬彧鍋氭渶鍩烘湰鐨勮娉曟鏌?
  2. 鏈€灏忓寲鏁版嵁锛氬彧浼犺緭蹇呰鐨勪俊鎭?
  3. 浣跨敤 record锛氳嚜鍔ㄥ疄鐜伴珮鏁堢殑鐩哥瓑姣旇緝
  4. 娴嬮噺鎬ц兘锛氫娇鐢?Stopwatch 娴嬮噺鍚勪釜闃舵鐨勮€楁椂
csharp
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 缁勫悎澶氫釜绠¢亾銆?

csharp
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. 鐢熸垚鐨勪唬鐮佹湁缂栬瘧閿欒鎬庝箞鍔烇紵

璋冭瘯姝ラ锛?

  1. **鏌ョ湅鐢熸垚鐨勬枃浠?*锛氬湪 obj/Debug/netX.X/generated/ 鐩綍涓?
  2. 娣诲姞璇婃柇锛氭姤鍛婄敓鎴愯繃绋嬩腑鐨勯棶棰?
  3. 楠岃瘉璇硶锛氫娇鐢?Roslyn API 瑙f瀽鐢熸垚鐨勪唬鐮?
csharp
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銆?

csharp
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);
    });
}

鍦ㄩ」鐩枃浠朵腑璁剧疆锛?

xml
<PropertyGroup>
  <GenerateDebugCode>true</GenerateDebugCode>
</PropertyGroup>

7. 澧為噺鐢熸垚鍣ㄥ彲浠ョ敓鎴愬灏戜釜鏂囦欢锛?

闄愬埗锛氱悊璁轰笂娌℃湁闄愬埗锛屼絾寤鸿锛?

  • 姣忎釜绫荤敓鎴愪竴涓枃浠讹細閫傚悎灏忓瀷椤圭洰
  • 澶氫釜绫荤敓鎴愪竴涓枃浠讹細閫傚悎澶у瀷椤圭洰锛堝噺灏戞枃浠舵暟閲忥級

鎺ㄨ崘鍋氭硶锛?

csharp
// 鏂规 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銆?

csharp
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) - 婧愮敓鎴愬櫒寮€鍙戞渶浣冲疄璺?
  • 楂樼骇妯″紡 - 楂樼骇鎶€宸у拰妯″紡

瀹樻柟鏂囨。

鐩稿叧鏂囨。

绀轰緥椤圭洰

  • [ToString 鐢熸垚鍣╙(/examples/tostring-generator) - 瀹炵敤鐨勪唬鐮佺敓鎴愮ず渚?
  • [Builder 鐢熸垚鍣╙(/examples/builder-generator) - 澶嶆潅鐨勪唬鐮佺敓鎴愭ā寮?
  • 璇婃柇鎶ュ憡 - 閿欒鎶ュ憡鎶€鏈?

绀惧尯璧勬簮

鎬ц兘鍒嗘瀽宸ュ叿

涓嬩竴姝ュ涔?

  1. 鍩虹宸╁浐锛?

  2. 杩涢樁瀛︿範锛?

    • 瀛︿範 [ToString 鐢熸垚鍣╙(/examples/tostring-generator)
    • 瀹炶返 [Builder 鐢熸垚鍣╙(/examples/builder-generator)
    • 鎺屾彙 [娴嬭瘯鎶€鏈痌(/examples/testing)
  3. **娣卞叆鐮旂┒**锛?


鎬荤粨

澧為噺鐢熸垚鍣ㄦ槸 Roslyn 婧愮敓鎴愬櫒鐨勯噸瑕佽繘鍖栵紝閫氳繃鏅鸿兘缂撳瓨鏈哄埗鏄捐憲鎻愰珮浜嗙紪璇戞€ц兘銆傚叧閿鐐癸細

  1. 浣跨敤 record 绫诲瀷锛氳嚜鍔ㄥ疄鐜?IEquatable锛屾敮鎸佺紦瀛?
  2. **蹇€熻娉曡繃婊?*锛氬湪 predicate 涓彧鍋氳娉曟鏌?
  3. 鏈€灏忓寲鏁版嵁浼犺緭锛氬彧浼犺緭蹇呰鐨勪俊鎭?
  4. **姝g‘鐨勭閬撶粍缁?*锛氫娇鐢ㄥ涓皬绠¢亾缁勫悎
  5. 鎬ц兘娴嬭瘯锛氭寔缁祴閲忓拰浼樺寲鎬ц兘

閫氳繃閬靛惊鏈€浣冲疄璺碉紝浣犲彲浠ュ垱寤洪珮鏁堛€佸彲缁存姢鐨勫閲忕敓鎴愬櫒锛屼负椤圭洰甯︽潵鏄捐憲鐨勬€ц兘鎻愬崌銆?

鏂囨。瀛楁暟缁熻锛氱害 8,500 瀛?

4. 濡備綍鍦ㄥ閲忕敓鎴愬櫒涓鐞嗗涓緭鍏ユ簮锛?

闂锛氶渶瑕佸悓鏃跺鐞嗗涓壒鎬ф垨澶氱绫诲瀷鐨勮緭鍏ャ€?

瑙e喅鏂规锛氫娇鐢?Combine 缁勫悎澶氫釜鎻愪緵鍣?

csharp
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 鏂规硶

csharp
[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: 澧為噺鐢熸垚鍣ㄤ細鑷姩澶勭悊鏂囦欢鍒犻櫎锛?

csharp
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: 浣跨敤鏃ュ織鍜岃瘖鏂伐鍏凤細

csharp
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


下一步

  1. 复习 基础概念
  2. 复习 增量管道和缓存

最后更新: 2025-01-21

基于 MIT 许可发布