Skip to content

Commit dfdf0d9

Browse files
committed
feat(EventHandler): 添加构造参数自定义支持并优化代码结构
- 在GenerateEventHandlerAttribute中新增ConstructorParameters和ConstructorBaseCall属性 - 移除SemanticModelCache和GenerateContentHash等冗余代码 - 重构EventHandlerSourceGenerator以使用共享的GetOrCreateSemanticModel方法 - 改进构造函数生成逻辑,支持自定义参数和基类调用
1 parent 0447c57 commit dfdf0d9

3 files changed

Lines changed: 53 additions & 109 deletions

File tree

Core/Mud.HttpUtils.Generator/EventHandler/EventHandlerSourceGenerator.cs

Lines changed: 39 additions & 97 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
// -----------------------------------------------------------------------
77

88
using System.Collections.Immutable;
9-
using System.Security.Cryptography;
109

1110
namespace Mud.HttpUtils;
1211

@@ -17,57 +16,6 @@ namespace Mud.HttpUtils;
1716
internal 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
}

Core/Mud.HttpUtils.Generator/Mud.HttpUtils.Generator.xml

Lines changed: 0 additions & 12 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Core/Mud.HttpUtils/Attributes/GenerateEventHandlerAttribute.cs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,4 +48,18 @@ public GenerateEventHandlerAttribute(string? eventType)
4848
/// 事件处理器类型。
4949
/// </summary>
5050
public string? EventType { get; set; }
51+
52+
/// <summary>
53+
/// 构造函数参数定义,格式:"Type1 param1,Type2 param2"。
54+
/// <para>示例: "IFeishuEventDeduplicator businessDeduplicator,ILogger logger"</para>
55+
/// <para>默认值: "IFeishuEventDeduplicator businessDeduplicator,ILogger logger"</para>
56+
/// </summary>
57+
public string? ConstructorParameters { get; set; }
58+
59+
/// <summary>
60+
/// 构造函数基类调用参数,格式:"param1,param2"。
61+
/// <para>示例: "businessDeduplicator,logger"</para>
62+
/// <para>默认值: "businessDeduplicator,logger"</para>
63+
/// </summary>
64+
public string? ConstructorBaseCall { get; set; }
5165
}

0 commit comments

Comments
 (0)