<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      大家好,我是token。今天想和大家聊聊C#源生成器這個神奇的技術。
      說起源生成器,可能很多同學會想:又是什么新的輪子?我反射用得好好的,為什么要學這個?別急,看完這篇文章,你就會發現源生成器簡直是性能優化的救命稻草,能讓你的應用快到飛起。

      源生成器到底是個啥?

      簡單來說,源生成器就是一個在編譯時幫你寫代碼的小助手。想象一下,你有一個非常勤快的實習生,每次編譯的時候,他都會根據你的要求自動生成一堆代碼,而且生成的代碼質量還特別高。

      傳統的做法是什么樣的呢?比如你想做個序列化:

      // 老式做法:運行時反射,慢得像蝸牛
      var json = JsonSerializer.Serialize(person); // 內部大量反射調用
      

      而源生成器的做法是:

      // 編譯時就生成好了序列化代碼,快得像火箭
      var json = JsonSerializer.Serialize(person, PersonContext.Default.Person);
      

      看起來差不多,但實際性能差了一個天地。

      為什么源生成器這么快?

      數據說話最有說服力。在序列化場景中,傳統反射需要734.563納秒,而源生成器只需要6.253納秒。這是117倍的性能提升!

      為什么會有這么大的差距呢?

      反射的痛點:

      • 運行時才開始分析類型結構
      • 需要緩存和管理大量元數據
      • 每次調用都有裝箱拆箱的開銷
      • GC壓力山大

      源生成器的優勢:

      • 編譯時就把所有工作做完了
      • 生成的代碼直接調用,沒有中間層
      • 零反射,零裝箱
      • 內存占用更低

      就像是你要做一道菜,反射是現場買菜現場切,而源生成器是提前把所有食材都準備好,直接下鍋。

      第一個源生成器:Hello World

      讓我們來寫一個最簡單的源生成器。首先創建一個新的類庫項目:

      <Project Sdk="Microsoft.NET.Sdk">
        <PropertyGroup>
          <TargetFramework>netstandard2.0</TargetFramework>
          <IsRoslynComponent>true</IsRoslynComponent>
          <IncludeBuildOutput>false</IncludeBuildOutput>
        </PropertyGroup>
        
        <ItemGroup>
          <PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.5.0" PrivateAssets="all" />
          <PackageReference Include="Microsoft.CodeAnalysis.Analyzers" Version="3.3.4" PrivateAssets="all" />
        </ItemGroup>
      </Project>
      

      然后寫一個簡單的生成器:

      [Generator]
      public class HelloWorldGenerator : ISourceGenerator
      {
          public void Initialize(GeneratorInitializationContext context)
          {
              // 初始化,一般用不到
          }
      
          public void Execute(GeneratorExecutionContext context)
          {
              var sourceCode = @"
      namespace Generated
      {
          public static class HelloWorld
          {
              public static string SayHello() => ""Hello from Source Generator!"";
          }
      }";
              context.AddSource("HelloWorld.g.cs", sourceCode);
          }
      }
      

      在消費項目中引用這個生成器:

      <ProjectReference Include="../HelloWorldGenerator/HelloWorldGenerator.csproj" 
                        OutputItemType="Analyzer" 
                        ReferenceOutputAssembly="false" />
      

      現在你可以直接使用生成的代碼:

      using Generated;
      
      Console.WriteLine(HelloWorld.SayHello()); // 輸出: Hello from Source Generator!
      

      進階技巧:增量源生成器

      上面的例子雖然能工作,但在大型項目中會有性能問題。每次編譯都會重新生成所有代碼,就像每次做飯都要重新洗所有的鍋一樣浪費。

      這時候就要用到增量源生成器了。它采用了類似React的虛擬DOM的思想,只有變化的部分才會重新生成:

      [Generator]
      public class SmartPropertyGenerator : IIncrementalGenerator
      {
          public void Initialize(IncrementalGeneratorInitializationContext context)
          {
              // 只關注有特定屬性的類
              var pipeline = context.SyntaxProvider
                  .ForAttributeWithMetadataName(
                      "MyNamespace.GeneratePropertiesAttribute",
                      predicate: static (node, _) => node is ClassDeclarationSyntax,
                      transform: static (ctx, _) => GetClassInfo(ctx))
                  .Where(static m => m is not null);
              
              context.RegisterSourceOutput(pipeline, GenerateProperties);
          }
          
          private static ClassInfo? GetClassInfo(GeneratorAttributeSyntaxContext context)
          {
              var classDeclaration = (ClassDeclarationSyntax)context.TargetNode;
              var symbol = context.TargetSymbol as INamedTypeSymbol;
              
              return new ClassInfo(
                  Name: symbol.Name,
                  Namespace: symbol.ContainingNamespace.ToDisplayString()
              );
          }
          
          private static void GenerateProperties(SourceProductionContext context, ClassInfo classInfo)
          {
              var source = $@"
      namespace {classInfo.Namespace}
      {{
          partial class {classInfo.Name}
          {{
              public string GeneratedProperty {{ get; set; }} = ""Auto-generated!"";
          }}
      }}";
              context.AddSource($"{classInfo.Name}.Properties.g.cs", source);
          }
      }
      
      public record ClassInfo(string Name, string Namespace);
      

      使用的時候只需要加個屬性:

      [GenerateProperties]
      public partial class Person
      {
          public string Name { get; set; }
          // GeneratedProperty 會被自動生成
      }
      

      實戰案例:FastService的妙用

      說到實際應用,不得不提一下FastService這個項目。它用源生成器簡化了ASP.NET Core的API開發,讓你寫API就像寫普通方法一樣簡單。

      傳統的Minimal API寫法:

      app.MapGet("/api/users", async (UserService service) => 
      {
          return await service.GetUsersAsync();
      });
      
      app.MapPost("/api/users", async (CreateUserRequest request, UserService service) =>
      {
          return await service.CreateUserAsync(request);
      });
      
      // 還有一大堆路由配置...
      

      用了FastService之后:

      [Route("/api/users")]
      [Tags("用戶管理")]
      public class UserService : FastApi
      {
          [EndpointSummary("獲取用戶列表")]
          public async Task<List<User>> GetUsersAsync()
          {
              return await GetAllUsersAsync();
          }
          
          [EndpointSummary("創建用戶")]
          public async Task<User> CreateUserAsync(CreateUserRequest request)
          {
              return await SaveUserAsync(request);
          }
      }
      

      源生成器會自動分析方法名,推斷HTTP方法類型:

      • Get* → GET請求
      • Create*, Add*, Post* → POST請求
      • Update*, Edit*, Put* → PUT請求
      • Delete*, Remove* → DELETE請求

      然后生成對應的路由注冊代碼。這樣既保持了強類型的優勢,又大大簡化了代碼編寫。

      性能優化的秘密武器

      在開發源生成器時,有幾個性能優化的小技巧:

      1. 早期過濾

      不要什么節點都分析,先用謂詞函數過濾掉不需要的:

      var pipeline = context.SyntaxProvider
          .CreateSyntaxProvider(
              predicate: static (node, _) => node is ClassDeclarationSyntax cls && 
                                            cls.AttributeLists.Count > 0, // 只看有屬性的類
              transform: static (ctx, _) => TransformNode(ctx))
      

      2. 使用值類型數據模型

      千萬不要在數據模型中保存Syntax或ISymbol對象,它們不能被正確緩存:

      // ? 錯誤做法
      public record ClassInfo(ClassDeclarationSyntax Syntax, INamedTypeSymbol Symbol);
      
      // ? 正確做法
      public readonly record struct ClassInfo(
          string Name,
          string Namespace,
          EquatableArray<PropertyInfo> Properties);
      

      3. 對象池優化

      對于頻繁創建的對象,使用對象池:

      private static readonly ObjectPool<StringBuilder> _stringBuilderPool = 
          new DefaultObjectPool<StringBuilder>(new StringBuilderPooledObjectPolicy());
      
      private static string GenerateCode(ClassInfo info)
      {
          var sb = _stringBuilderPool.Get();
          try
          {
              sb.AppendLine($"namespace {info.Namespace}");
              // 生成代碼...
              return sb.ToString();
          }
          finally
          {
              _stringBuilderPool.Return(sb);
          }
      }
      

      調試技巧:不再抓瞎

      源生成器的調試曾經是個大難題,但現在有了不少好用的技巧。

      1. 斷點調試

      在源生成器代碼中加入:

      public void Initialize(IncrementalGeneratorInitializationContext context)
      {
      #if DEBUG
          if (!Debugger.IsAttached)
          {
              Debugger.Launch(); // 會彈出調試器選擇界面
          }
      #endif
      }
      

      2. 查看生成的代碼

      在項目文件中加入:

      <PropertyGroup>
        <EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles>
        <CompilerGeneratedFilesOutputPath>Generated</CompilerGeneratedFilesOutputPath>
      </PropertyGroup>
      

      編譯后,生成的代碼會保存在Generated文件夾中,你可以直接查看。

      3. 單元測試

      寫個測試來驗證生成器的行為:

      [Test]
      public void Should_Generate_Property_For_Marked_Class()
      {
          var source = @"
      using MyNamespace;
      
      [GenerateProperties]
      public partial class TestClass
      {
      }";
      
          var result = RunGenerator(source);
          
          Assert.That(result, Contains.Substring("public string GeneratedProperty"));
      }
      

      常見陷阱與避坑指南

      開發源生成器時,有幾個坑是新手經常掉進去的:

      1. 命名空間沖突

      生成的代碼可能和現有代碼沖突,記得加上合適的命名空間或者前綴:

      // 生成的代碼加上特殊前綴
      var className = $"Generated_{originalClassName}";
      

      2. 編譯錯誤處理

      當生成的代碼有語法錯誤時,編譯器的錯誤信息可能不夠清晰。建議在生成器中添加診斷信息:

      public static readonly DiagnosticDescriptor InvalidClassError = new(
          id: "SG001",
          title: "Invalid class for generation",
          messageFormat: "The class '{0}' must be partial to use this generator",
          category: "SourceGenerator",
          DiagnosticSeverity.Error,
          isEnabledByDefault: true);
      
      // 在生成器中使用
      context.ReportDiagnostic(Diagnostic.Create(InvalidClassError, location, className));
      

      3. 增量生成緩存失效

      如果數據模型設計不當,可能導致緩存頻繁失效:

      // ? 這樣會導致緩存失效,因為Compilation對象每次都不同
      var hasRef = context.Compilation.Select(comp => comp.ReferencedAssemblyNames.Any(...));
      
      // ? 正確的做法
      var hasRef = context.CompilationProvider.Select(comp => 
          comp.ReferencedAssemblyNames.Select(name => name.Name).OrderBy(x => x).ToArray());
      

      生態系統現狀

      目前已經有不少成熟的源生成器項目:

      • System.Text.Json - 微軟官方的JSON序列化優化
      • Mapperly - 對象映射生成器
      • FastService - API開發簡化
      • StronglyTypedId - 強類型ID生成
      • Meziantou.Framework.StronglyTypedId - 另一個強類型ID實現

      這些項目都是學習源生成器的好例子,推薦大家去看看源碼。

      總結

      源生成器真的是一個很酷的技術。它不僅能大幅提升應用性能,還能讓我們寫出更簡潔、更高效的代碼。雖然學習曲線有點陡峭,但一旦掌握了,你會發現很多以前覺得復雜的問題都能用源生成器優雅地解決。

      如果你還在用傳統的反射做序列化、映射這些工作,不妨試試源生成器。相信我,一旦體驗過那種編譯時生成代碼的快感,你就再也回不去了。

      最后,學習新技術最好的方法就是動手實踐。建議大家從簡單的Hello World開始,然后逐步嘗試更復雜的場景。記住,代碼是寫給人看的,源生成器也不例外。寫出清晰、可維護的生成器代碼,比寫出復雜炫技的代碼更有價值。

      Happy coding!

      posted on 2025-07-12 00:31  239573049  閱讀(2073)  評論(2)    收藏  舉報



      主站蜘蛛池模板: 99久久精品费精品国产一区二| 亚洲一区精品视频在线| 亚洲无线码在线一区观看| 9l精品人妻中文字幕色| 国产激情无码一区二区三区| 桃花岛亚洲成在人线AV| 国产乱码日产乱码精品精| 日韩人妻系列无码专区| 亚洲精品麻豆一区二区| 国产精品无遮挡猛进猛出| 亚洲人妻一区二区精品| 亚洲伊人成无码综合网| 精品国产欧美一区二区三区在线| 开心五月激情五月俺亚洲| 无码av最新无码av专区| 免费无码成人AV片在线| 亚洲中少妇久久中文字幕| 91精品国产福利尤物免费| 日韩中文字幕精品人妻| 国产精品视频一区二区噜| 亚洲国产成人久久综合野外| 兰溪市| 伊人久久大香线蕉综合网| 亚洲精品成人福利网站| 甘谷县| 香港日本三级亚洲三级| 少妇粗大进出白浆嘿嘿视频| 隆子县| 日韩永久永久永久黄色大片| 亚洲成人av免费一区| 午夜羞羞影院男女爽爽爽| 麻豆天美国产一区在线播放| 亚洲VA欧美VA国产综合| 国产精品入口中文字幕| 亚洲a免费| 巨胸不知火舞露双奶头无遮挡| 人妻少妇偷人一区二区| 免费无码肉片在线观看| av无码av无码专区| 97se亚洲国产综合自在线观看| 亚洲色婷婷综合开心网|