mirror of
https://github.com/GeWuYou/GFramework.git
synced 2026-03-22 19:03:29 +08:00
- 新增 ContextAwareExtensions 扩展类,提供便捷的上下文访问方法 - 为 IContextAware 接口添加 GetContext 方法以获取架构上下文 - 更新 ContextAwareBase 基类实现 GetContext 方法 - 改进源代码生成器的 Generate 方法参数结构 - 重构 ContextAwareGenerator 生成器实现接口方法自动实现 - 更新单元测试以验证新生成的上下文感知代码正确性
109 lines
3.7 KiB
C#
109 lines
3.7 KiB
C#
using System;
|
||
using System.Linq;
|
||
using System.Text;
|
||
using GFramework.SourceGenerators.Abstractions.logging;
|
||
using GFramework.SourceGenerators.Common.constants;
|
||
using GFramework.SourceGenerators.Common.generator;
|
||
using Microsoft.CodeAnalysis;
|
||
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
||
|
||
namespace GFramework.SourceGenerators.logging;
|
||
|
||
/// <summary>
|
||
/// 日志生成器,用于为标记了LogAttribute的类自动生成日志字段
|
||
/// </summary>
|
||
[Generator]
|
||
public sealed class LoggerGenerator : TypeAttributeClassGeneratorBase
|
||
{
|
||
/// <summary>
|
||
/// 获取属性元数据的完整名称,用于标识日志属性的完全限定名
|
||
/// </summary>
|
||
protected override Type AttributeType => typeof(LogAttribute);
|
||
|
||
/// <summary>
|
||
/// 用于语法快速筛选
|
||
/// </summary>
|
||
protected override string AttributeShortNameWithoutSuffix => "Log";
|
||
|
||
|
||
/// <summary>
|
||
/// 对类进行额外语义校验(可选)
|
||
/// </summary>
|
||
protected override bool ValidateSymbol(
|
||
SourceProductionContext context,
|
||
Compilation compilation,
|
||
ClassDeclarationSyntax syntax,
|
||
INamedTypeSymbol symbol,
|
||
AttributeData attr)
|
||
{
|
||
// 可以加自定义规则,比如确保类是 public 或实现某接口
|
||
return true;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 生成源代码
|
||
/// </summary>
|
||
/// <param name="context">源生产上下文</param>
|
||
/// <param name="compilation">编译对象</param>
|
||
/// <param name="symbol">命名类型符号</param>
|
||
/// <param name="attr">属性数据</param>
|
||
/// <returns>生成的源代码字符串</returns>
|
||
protected override string Generate(
|
||
SourceProductionContext context,
|
||
Compilation compilation,
|
||
INamedTypeSymbol symbol,
|
||
AttributeData attr)
|
||
{
|
||
var ns = symbol.ContainingNamespace.IsGlobalNamespace
|
||
? null
|
||
: symbol.ContainingNamespace.ToDisplayString();
|
||
|
||
var className = symbol.Name;
|
||
|
||
// 解析构造函数参数
|
||
var name = className;
|
||
if (attr.ConstructorArguments.Length > 0)
|
||
{
|
||
var argValue = attr.ConstructorArguments[0].Value;
|
||
name = argValue is string s && !string.IsNullOrWhiteSpace(s)
|
||
? s
|
||
: className;
|
||
}
|
||
|
||
// 解析命名参数
|
||
var fieldName = GetNamedArg(attr, "FieldName")?.ToString() ?? "_log";
|
||
var access = GetNamedArg(attr, "AccessModifier")?.ToString() ?? "private";
|
||
var isStaticObj = GetNamedArg(attr, "IsStatic");
|
||
var isStatic = isStaticObj is not bool b || b; // 默认 true
|
||
var staticKeyword = isStatic ? "static " : "";
|
||
|
||
var sb = new StringBuilder();
|
||
sb.AppendLine("// <auto-generated />");
|
||
sb.AppendLine($"using {PathContests.CoreAbstractionsNamespace}.logging;");
|
||
sb.AppendLine($"using {PathContests.CoreNamespace}.logging;");
|
||
|
||
if (ns is not null)
|
||
{
|
||
sb.AppendLine($"namespace {ns};");
|
||
sb.AppendLine();
|
||
}
|
||
|
||
sb.AppendLine($"partial class {className}");
|
||
sb.AppendLine("{");
|
||
sb.AppendLine(" /// <summary>Auto-generated logger</summary>");
|
||
sb.AppendLine(
|
||
$" {access} {staticKeyword}readonly ILogger {fieldName} = new ConsoleLoggerFactory().GetLogger(\"{name}\");");
|
||
sb.AppendLine("}");
|
||
|
||
return sb.ToString().TrimEnd();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 可以自定义生成文件名
|
||
/// </summary>
|
||
protected override string GetHintName(INamedTypeSymbol symbol)
|
||
=> $"{symbol.Name}.Logger.g.cs";
|
||
|
||
private static object? GetNamedArg(AttributeData attr, string name)
|
||
=> attr.NamedArguments.FirstOrDefault(kv => kv.Key == name).Value.Value;
|
||
} |