1+ // ------------------------------------------------------------------------------
2+ // 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有
3+ // 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权
4+ // CSDN博客:https://blog.csdn.net/qq_40374647
5+ // 哔哩哔哩视频:https://space.bilibili.com/94253567
6+ // Gitee源代码仓库:https://gitee.com/RRQM_Home
7+ // Github源代码仓库:https://github.com/RRQM
8+ // API首页:https://touchsocket.net/
9+ // 交流QQ群:234762506
10+ // 感谢您的下载和使用
11+ // ------------------------------------------------------------------------------
12+
113using Microsoft . CodeAnalysis ;
214using Microsoft . CodeAnalysis . CSharp ;
315using Microsoft . CodeAnalysis . CSharp . Syntax ;
416using Microsoft . CodeAnalysis . Text ;
517using System ;
618using System . Collections . Generic ;
719using System . Collections . Immutable ;
8- using System . Diagnostics ;
920using System . IO ;
1021using System . Linq ;
22+ using System . Reflection ;
1123using System . Text ;
1224
1325namespace CodeInject ;
@@ -17,16 +29,28 @@ public class CodeInjectIncrementalSourceGenerator : IIncrementalGenerator
1729{
1830 public void Initialize ( IncrementalGeneratorInitializationContext context )
1931 {
32+ // 获取项目中的源文件
33+ var sourceFiles = context . SyntaxProvider
34+ . CreateSyntaxProvider (
35+ predicate : static ( s , _ ) => s is CompilationUnitSyntax ,
36+ transform : static ( ctx , _ ) => ctx )
37+ . Where ( static ctx => ctx . Node is CompilationUnitSyntax ) ;
38+
2039 // 添加 attribute 源码到消费项目
21- context . RegisterPostInitializationOutput ( ctx => ctx . AddSource (
22- "RegionInjectAttribute.g.cs" ,
23- SourceText . From ( AttributeSource , Encoding . UTF8 ) ) ) ;
40+ context . RegisterSourceOutput ( sourceFiles . Collect ( ) , ( ctx , sources ) =>
41+ {
42+ var attributeSource = GetAttributeSourceFromEmbeddedResource ( ) ;
43+ if ( ! string . IsNullOrEmpty ( attributeSource ) )
44+ {
45+ ctx . AddSource ( "RegionInjectAttribute.g.cs" , SourceText . From ( attributeSource , Encoding . UTF8 ) ) ;
46+ }
47+ } ) ;
2448
2549 // 获取所有的 AdditionalFiles
26- IncrementalValuesProvider < AdditionalText > additionalFiles = context . AdditionalTextsProvider ;
50+ var additionalFiles = context . AdditionalTextsProvider ;
2751
2852 // 查找所有标记了 RegionInjectAttribute 的类
29- IncrementalValuesProvider < ClassToGenerate > classDeclarations = context . SyntaxProvider
53+ var classDeclarations = context . SyntaxProvider
3054 . CreateSyntaxProvider (
3155 predicate : static ( s , _ ) => IsSyntaxTargetForGeneration ( s ) ,
3256 transform : static ( ctx , _ ) => GetSemanticTargetForGeneration ( ctx ) )
@@ -39,10 +63,69 @@ public void Initialize(IncrementalGeneratorInitializationContext context)
3963 static ( spc , source ) => Execute ( source . Left , source . Right , spc ) ) ;
4064 }
4165
42- static bool IsSyntaxTargetForGeneration ( SyntaxNode node )
66+ /// <summary>
67+ /// 获取程序集中的嵌入资源内容
68+ /// </summary>
69+ /// <param name="resourceName">资源名称,如果为null则返回所有资源名称</param>
70+ /// <returns>资源内容或资源名称列表</returns>
71+ private static string GetEmbeddedResourceContent ( string resourceName = null )
72+ {
73+ var assembly = Assembly . GetExecutingAssembly ( ) ;
74+ var resourceNames = assembly . GetManifestResourceNames ( ) ;
75+
76+ // 如果没有指定资源名称,返回所有资源名称
77+ if ( string . IsNullOrEmpty ( resourceName ) )
78+ {
79+ return string . Join ( Environment . NewLine , resourceNames ) ;
80+ }
81+
82+ // 查找匹配的资源
83+ var targetResource = resourceNames . FirstOrDefault ( name =>
84+ name . Equals ( resourceName , StringComparison . OrdinalIgnoreCase ) ||
85+ name . EndsWith ( $ ".{ resourceName } ", StringComparison . OrdinalIgnoreCase ) ) ;
86+
87+ if ( string . IsNullOrEmpty ( targetResource ) )
88+ {
89+ return null ;
90+ }
91+
92+ try
93+ {
94+ using ( var stream = assembly . GetManifestResourceStream ( targetResource ) )
95+ {
96+ if ( stream == null )
97+ return null ;
98+
99+ using ( var reader = new StreamReader ( stream , Encoding . UTF8 ) )
100+ {
101+ return reader . ReadToEnd ( ) ;
102+ }
103+ }
104+ }
105+ catch
106+ {
107+ return null ;
108+ }
109+ }
110+
111+ private static string GetAttributeSourceFromEmbeddedResource ( )
112+ {
113+ // 尝试从嵌入资源中获取 RegionInjectAttribute 的源代码
114+ var resourceContent = GetEmbeddedResourceContent ( "RegionInjectAttribute.cs" ) ;
115+
116+ // 如果找不到嵌入资源,使用默认的源代码
117+ if ( string . IsNullOrEmpty ( resourceContent ) )
118+ {
119+ return DefaultAttributeSource ;
120+ }
121+
122+ return resourceContent ;
123+ }
124+
125+ private static bool IsSyntaxTargetForGeneration ( SyntaxNode node )
43126 => node is ClassDeclarationSyntax c && c . AttributeLists . Count > 0 ;
44127
45- static ClassToGenerate GetSemanticTargetForGeneration ( GeneratorSyntaxContext context )
128+ private static ClassToGenerate GetSemanticTargetForGeneration ( GeneratorSyntaxContext context )
46129 {
47130 try
48131 {
@@ -75,7 +158,7 @@ static ClassToGenerate GetSemanticTargetForGeneration(GeneratorSyntaxContext con
75158 // 从构造函数参数获取占位符
76159 if ( attributeData . ConstructorArguments . Length > 2 )
77160 {
78- for ( int i = 2 ; i < attributeData . ConstructorArguments . Length ; i ++ )
161+ for ( var i = 2 ; i < attributeData . ConstructorArguments . Length ; i ++ )
79162 {
80163 var value = attributeData . ConstructorArguments [ i ] . Value ? . ToString ( ) ;
81164 if ( ! string . IsNullOrEmpty ( value ) )
@@ -123,7 +206,7 @@ static ClassToGenerate GetSemanticTargetForGeneration(GeneratorSyntaxContext con
123206 }
124207 }
125208
126- static string GetNamespace ( ClassDeclarationSyntax classDeclaration )
209+ private static string GetNamespace ( ClassDeclarationSyntax classDeclaration )
127210 {
128211 var namespaceDeclaration = classDeclaration . Ancestors ( ) . OfType < NamespaceDeclarationSyntax > ( ) . FirstOrDefault ( ) ;
129212 if ( namespaceDeclaration != null )
@@ -136,7 +219,7 @@ static string GetNamespace(ClassDeclarationSyntax classDeclaration)
136219 return string . Empty ;
137220 }
138221
139- static void Execute ( ImmutableArray < ClassToGenerate > classes , ImmutableArray < AdditionalText > additionalFiles , SourceProductionContext context )
222+ private static void Execute ( ImmutableArray < ClassToGenerate > classes , ImmutableArray < AdditionalText > additionalFiles , SourceProductionContext context )
140223 {
141224 if ( classes . IsDefaultOrEmpty )
142225 return ;
@@ -151,7 +234,7 @@ static void Execute(ImmutableArray<ClassToGenerate> classes, ImmutableArray<Addi
151234 }
152235 }
153236
154- static string GenerateClass ( ClassToGenerate classInfo , ImmutableArray < AdditionalText > additionalFiles , SourceProductionContext context )
237+ private static string GenerateClass ( ClassToGenerate classInfo , ImmutableArray < AdditionalText > additionalFiles , SourceProductionContext context )
155238 {
156239 var sb = new StringBuilder ( ) ;
157240
@@ -192,7 +275,7 @@ static string GenerateClass(ClassToGenerate classInfo, ImmutableArray<Additional
192275 return sb . ToString ( ) ;
193276 }
194277
195- static string FormatInjectedCode ( string code , string indentation )
278+ private static string FormatInjectedCode ( string code , string indentation )
196279 {
197280 if ( string . IsNullOrEmpty ( code ) )
198281 return string . Empty ;
@@ -218,26 +301,26 @@ static string FormatInjectedCode(string code, string indentation)
218301 return string . Join ( "\r \n " , formattedLines ) ;
219302 }
220303
221- static string ExtractAndProcessRegion ( RegionInjectData attribute , ImmutableArray < AdditionalText > additionalFiles , SourceProductionContext context )
304+ private static string ExtractAndProcessRegion ( RegionInjectData attribute , ImmutableArray < AdditionalText > additionalFiles , SourceProductionContext context )
222305 {
223306 // 首先尝试从 AdditionalFiles 中查找文件
224307 string fileContent = null ;
225308 AdditionalText targetFile = null ;
226309
227310 // 规范化路径以进行比较
228311 var normalizedTargetPath = attribute . FilePath . Replace ( '\\ ' , '/' ) ;
229-
312+
230313 foreach ( var file in additionalFiles )
231314 {
232315 var filePath = file . Path . Replace ( '\\ ' , '/' ) ;
233-
316+
234317 // 检查完整路径匹配
235318 if ( filePath . EndsWith ( normalizedTargetPath , StringComparison . OrdinalIgnoreCase ) )
236319 {
237320 targetFile = file ;
238321 break ;
239322 }
240-
323+
241324 // 检查文件名匹配
242325 var fileName = Path . GetFileName ( normalizedTargetPath ) ;
243326 if ( Path . GetFileName ( filePath ) . Equals ( fileName , StringComparison . OrdinalIgnoreCase ) )
@@ -301,17 +384,17 @@ static string ExtractAndProcessRegion(RegionInjectData attribute, ImmutableArray
301384 return ProcessPlaceholders ( regionContent , attribute . Placeholders ) ;
302385 }
303386
304- static string ExtractRegion ( string fileContent , string regionName )
387+ private static string ExtractRegion ( string fileContent , string regionName )
305388 {
306389 var lines = fileContent . Split ( new [ ] { '\r ' , '\n ' } , StringSplitOptions . None ) ;
307390 var regionStart = - 1 ;
308391 var regionEnd = - 1 ;
309392 var nestedLevel = 0 ;
310393
311- for ( int i = 0 ; i < lines . Length ; i ++ )
394+ for ( var i = 0 ; i < lines . Length ; i ++ )
312395 {
313396 var line = lines [ i ] . Trim ( ) ;
314-
397+
315398 if ( line . StartsWith ( "#region" ) )
316399 {
317400 if ( regionStart == - 1 && line . Contains ( regionName ) )
@@ -360,15 +443,15 @@ static string ExtractRegion(string fileContent, string regionName)
360443 return string . Join ( "\r \n " , processedLines ) ;
361444 }
362445
363- static string ProcessPlaceholders ( string content , string [ ] placeholders )
446+ private static string ProcessPlaceholders ( string content , string [ ] placeholders )
364447 {
365448 if ( placeholders . Length == 0 )
366449 return content ;
367450
368451 var result = content ;
369452
370453 // 处理成对的占位符 (key, value, key, value, ...)
371- for ( int i = 0 ; i < placeholders . Length - 1 ; i += 2 )
454+ for ( var i = 0 ; i < placeholders . Length - 1 ; i += 2 )
372455 {
373456 if ( i + 1 < placeholders . Length )
374457 {
@@ -386,7 +469,7 @@ static string ProcessPlaceholders(string content, string[] placeholders)
386469 return result ;
387470 }
388471
389- private const string AttributeSource = @"
472+ private const string DefaultAttributeSource = @"
390473using System;
391474
392475namespace CodeInject
@@ -420,9 +503,9 @@ internal class ClassToGenerate
420503
421504 public ClassToGenerate ( string name , string @namespace , RegionInjectData [ ] attributes )
422505 {
423- Name = name ;
424- Namespace = @namespace ;
425- Attributes = attributes ;
506+ this . Name = name ;
507+ this . Namespace = @namespace ;
508+ this . Attributes = attributes ;
426509 }
427510 }
428511
@@ -435,10 +518,10 @@ internal class RegionInjectData
435518
436519 public RegionInjectData ( string filePath , string regionName , string [ ] placeholders , Location location )
437520 {
438- FilePath = filePath ;
439- RegionName = regionName ;
440- Placeholders = placeholders ;
441- Location = location ;
521+ this . FilePath = filePath ;
522+ this . RegionName = regionName ;
523+ this . Placeholders = placeholders ;
524+ this . Location = location ;
442525 }
443526 }
444527}
0 commit comments