66// -----------------------------------------------------------------------
77
88using System . Collections . Immutable ;
9- using System . Security . Cryptography ;
109
1110namespace Mud . HttpUtils ;
1211
@@ -17,57 +16,6 @@ namespace Mud.HttpUtils;
1716internal class EventHandlerSourceGenerator : TransitiveCodeGenerator
1817{
1918 private const string EventHandlerAttributeName = "GenerateEventHandlerAttribute" ;
20- private const int MaxSemanticModelCacheSize = 100 ;
21-
22- /// <summary>
23- /// LRU缓存管理SemanticModel
24- /// </summary>
25- private sealed class SemanticModelCache
26- {
27- private readonly Dictionary < SyntaxTree , ( SemanticModel Model , LinkedListNode < SyntaxTree > Node ) > _cache ;
28- private readonly LinkedList < SyntaxTree > _lruList ;
29- private readonly int _maxSize ;
30- private readonly object _lock = new ( ) ;
31-
32- public SemanticModelCache ( int maxSize )
33- {
34- _cache = new Dictionary < SyntaxTree , ( SemanticModel , LinkedListNode < SyntaxTree > ) > ( ) ;
35- _lruList = new LinkedList < SyntaxTree > ( ) ;
36- _maxSize = maxSize ;
37- }
38-
39- public SemanticModel GetOrCreate ( SyntaxTree syntaxTree , Compilation compilation )
40- {
41- lock ( _lock )
42- {
43- if ( _cache . TryGetValue ( syntaxTree , out var cachedEntry ) )
44- {
45- // 更新LRU: 移到链表头部
46- _lruList . Remove ( cachedEntry . Node ) ;
47- _lruList . AddFirst ( cachedEntry . Node ) ;
48- return cachedEntry . Model ;
49- }
50-
51- // 创建新的SemanticModel
52- var model = compilation . GetSemanticModel ( syntaxTree ) ;
53- var node = _lruList . AddFirst ( syntaxTree ) ;
54- _cache [ syntaxTree ] = ( model , node ) ;
55-
56- // 超出上限时淘汰最久未使用的项
57- if ( _cache . Count > _maxSize )
58- {
59- var last = _lruList . Last ? . Value ;
60- if ( last != null )
61- {
62- _lruList . RemoveLast ( ) ;
63- _cache . Remove ( last ) ;
64- }
65- }
66-
67- return model ;
68- }
69- }
70- }
7119
7220 /// <inheritdoc/>
7321 protected override Collection < string > GetFileUsingNameSpaces ( )
@@ -115,18 +63,14 @@ private void ExecuteGenerator(
11563 if ( eventHandlerClasses . IsDefaultOrEmpty )
11664 return ;
11765
118- // 使用 LRU 缓存管理 SemanticModel
119- var semanticModelCache = new SemanticModelCache ( MaxSemanticModelCacheSize ) ;
120-
12166 foreach ( var eventClass in eventHandlerClasses )
12267 {
12368 if ( eventClass == null )
12469 continue ;
12570
12671 try
12772 {
128- // 从缓存获取或创建 SemanticModel
129- var semanticModel = semanticModelCache . GetOrCreate ( eventClass . SyntaxTree , compilation ) ;
73+ var semanticModel = HttpInvokeBaseSourceGenerator . GetOrCreateSemanticModel ( compilation , eventClass . SyntaxTree ) ;
13074
13175 var classSymbol = semanticModel . GetDeclaredSymbol ( eventClass ) ;
13276
@@ -145,13 +89,7 @@ private void ExecuteGenerator(
14589 if ( ! string . IsNullOrEmpty ( generatedCode ) )
14690 {
14791 var fileName = GenerateUniqueFileName ( eventClass , classSymbol , eventHandlerAttribute ) ;
148- var contentHash = GenerateContentHash ( generatedCode ) ;
149-
150- // 添加哈希注释到生成代码
151- var generatedCodeWithHash = generatedCode . TrimEnd ( ) +
152- $ "\n // ContentHash: { contentHash } ";
153-
154- context . AddSource ( fileName , generatedCodeWithHash ) ;
92+ context . AddSource ( fileName , generatedCode ) ;
15593 }
15694 }
15795 catch ( Exception ex )
@@ -186,10 +124,12 @@ private string GenerateEventHandlerClass(
186124 // 解析特性参数,使用AttributeDataHelper的已有功能
187125 var handlerNamespace = GetAttributeParameter ( eventHandlerAttribute , "HandlerNamespace" , "" ) ;
188126 var handlerClassName = GetAttributeParameter ( eventHandlerAttribute , "HandlerClassName" , "" ) ;
189- var eventType = AttributeDataHelper . GetStringValueFromAttributeConstructor ( eventHandlerAttribute , "EventType" )
190- ?? AttributeDataHelper . GetStringValueFromAttribute ( eventHandlerAttribute , "EventType" , " ")
127+ var eventType = AttributeDataHelper . GetStringValueFromAttribute ( eventHandlerAttribute , "EventType" , " ")
128+ ?? AttributeDataHelper . GetStringValueFromAttributeConstructor ( eventHandlerAttribute , "EventType" )
191129 ?? "" ;
192130 var inheritedFrom = GetAttributeParameter ( eventHandlerAttribute , "InheritedFrom" , "IdempotentFeishuEventHandler" ) ;
131+ var constructorParams = GetAttributeParameter ( eventHandlerAttribute , "ConstructorParameters" , "IFeishuEventDeduplicator businessDeduplicator,ILogger logger" ) ;
132+ var constructorBaseCall = GetAttributeParameter ( eventHandlerAttribute , "ConstructorBaseCall" , "businessDeduplicator,logger" ) ;
193133
194134 // 验证基类名合法性
195135 if ( ! ValidateBaseClassName ( inheritedFrom , context , eventClass . GetLocation ( ) ) )
@@ -210,13 +150,16 @@ private string GenerateEventHandlerClass(
210150 GenerateFileHeader ( sb ) ;
211151
212152 // 添加自定义命名空间引用(如果需要的话)
213- if ( ! string . IsNullOrEmpty ( inheritedFrom ) && inheritedFrom . Contains ( "." ) )
153+ if ( ! string . IsNullOrEmpty ( inheritedFrom ) )
214154 {
215- var parts = inheritedFrom . Split ( '.' ) ;
216- var inheritedNamespace = string . Join ( "." , parts . Take ( parts . Length - 1 ) ) ;
217- if ( ! GetFileUsingNameSpaces ( ) . Contains ( inheritedNamespace ) )
155+ var lastDotIndex = inheritedFrom . LastIndexOf ( '.' ) ;
156+ if ( lastDotIndex > 0 )
218157 {
219- sb . AppendLine ( $ "using { inheritedNamespace } ;") ;
158+ var inheritedNamespace = inheritedFrom . Substring ( 0 , lastDotIndex ) ;
159+ if ( ! GetFileUsingNameSpaces ( ) . Contains ( inheritedNamespace ) )
160+ {
161+ sb . AppendLine ( $ "using { inheritedNamespace } ;") ;
162+ }
220163 }
221164 }
222165
@@ -246,17 +189,30 @@ private string GenerateEventHandlerClass(
246189 sb . AppendLine ( " {" ) ;
247190
248191 // 构造函数
249- sb . AppendLine ( " /// <summary>" ) ;
250- sb . AppendLine ( " /// 默认构造函数" ) ;
251- sb . AppendLine ( " /// </summary>" ) ;
252- sb . AppendLine ( " /// <param name=\" businessDeduplicator\" >飞书事件去重服务接口</param>" ) ;
253- sb . AppendLine ( " /// <param name=\" logger\" >日志记录对象。</param>" ) ;
254- sb . AppendLine ( $ " { GeneratedCodeConsts . HttpGeneratedCodeAttribute } ") ;
255- sb . AppendLine ( $ " public { generatedClassName } (IFeishuEventDeduplicator businessDeduplicator, ILogger logger)") ;
256- sb . AppendLine ( " : base(businessDeduplicator,logger)" ) ;
257- sb . AppendLine ( " {" ) ;
258- sb . AppendLine ( " }" ) ;
259- sb . AppendLine ( ) ;
192+ if ( ! string . IsNullOrEmpty ( constructorParams ) )
193+ {
194+ sb . AppendLine ( " /// <summary>" ) ;
195+ sb . AppendLine ( " /// 默认构造函数" ) ;
196+ sb . AppendLine ( " /// </summary>" ) ;
197+
198+ var paramParts = constructorParams . Split ( ',' ) ;
199+ foreach ( var param in paramParts )
200+ {
201+ var trimmedParam = param . Trim ( ) ;
202+ var paramName = trimmedParam . Contains ( ' ' ) ? trimmedParam . Substring ( trimmedParam . LastIndexOf ( ' ' ) + 1 ) : trimmedParam ;
203+ sb . AppendLine ( $ " /// <param name=\" { paramName } \" >参数</param>") ;
204+ }
205+
206+ sb . AppendLine ( $ " { GeneratedCodeConsts . HttpGeneratedCodeAttribute } ") ;
207+ sb . AppendLine ( $ " public { generatedClassName } ({ constructorParams . Trim ( ) } )") ;
208+ if ( ! string . IsNullOrEmpty ( constructorBaseCall ) )
209+ {
210+ sb . AppendLine ( $ " : base({ constructorBaseCall . Trim ( ) } )") ;
211+ }
212+ sb . AppendLine ( " {" ) ;
213+ sb . AppendLine ( " }" ) ;
214+ sb . AppendLine ( ) ;
215+ }
260216
261217 // SupportedEventType属性
262218 if ( ! string . IsNullOrEmpty ( eventType ) )
@@ -286,7 +242,7 @@ private string GetAttributeParameter(AttributeData attribute, string parameterNa
286242 {
287243 // 优先使用AttributeDataHelper的命名参数方法
288244 var namedValue = AttributeDataHelper . GetStringValueFromAttribute ( attribute , parameterName , defaultValue ) ;
289- if ( ! string . IsNullOrEmpty ( namedValue ) && namedValue != defaultValue )
245+ if ( ! string . IsNullOrEmpty ( namedValue ) )
290246 {
291247 return namedValue ;
292248 }
@@ -456,18 +412,4 @@ private string GenerateUniqueFileName(
456412 return $ "{ namespacePart } _{ className } .g.cs";
457413 }
458414
459- /// <summary>
460- /// 生成内容哈希,用于增量编译的幂等性校验
461- /// </summary>
462- /// <param name="content">生成的内容</param>
463- /// <returns>SHA256哈希值的前8位</returns>
464- private string GenerateContentHash ( string content )
465- {
466- if ( string . IsNullOrEmpty ( content ) )
467- return string . Empty ;
468-
469- using var sha256 = SHA256 . Create ( ) ;
470- var hashBytes = sha256 . ComputeHash ( Encoding . UTF8 . GetBytes ( content ) ) ;
471- return BitConverter . ToString ( hashBytes ) . Replace ( "-" , "" ) . Substring ( 0 , 8 ) ;
472- }
473415}
0 commit comments