From 14894814a515d49f50fbc393f6785ca43dc5aab2 Mon Sep 17 00:00:00 2001
From: GeWuYou <95328647+GeWuYou@users.noreply.github.com>
Date: Wed, 14 Jan 2026 13:36:32 +0800
Subject: [PATCH] =?UTF-8?q?refactor(logging):=20=E9=87=8D=E6=9E=84?=
=?UTF-8?q?=E6=97=A5=E5=BF=97=E7=94=9F=E6=88=90=E5=99=A8=E4=BB=A3=E7=A0=81?=
=?UTF-8?q?=E7=BB=93=E6=9E=84?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- 添加AttributeData扩展方法用于获取命名参数和构造函数参数
- 引入GenericInfo记录结构体处理泛型信息
- 将INamedTypeSymbol扩展方法转换为扩展方法语法
- 添加ResolveGenerics方法解析泛型参数和约束条件
- 简化LoggerGenerator中的参数解析逻辑
- 移除不再需要的GetNamedArg私有方法
- 优化代码可读性和维护性
---
.../extensions/AttributeDataExtensions.cs | 47 +++++++
.../extensions/INamedTypeSymbolExtensions.cs | 115 ++++++++++++------
.../info/GenericInfo.cs | 13 ++
.../logging/LoggerGenerator.cs | 101 ++++-----------
4 files changed, 167 insertions(+), 109 deletions(-)
create mode 100644 GFramework.SourceGenerators.Common/extensions/AttributeDataExtensions.cs
create mode 100644 GFramework.SourceGenerators.Common/info/GenericInfo.cs
diff --git a/GFramework.SourceGenerators.Common/extensions/AttributeDataExtensions.cs b/GFramework.SourceGenerators.Common/extensions/AttributeDataExtensions.cs
new file mode 100644
index 0000000..6aaeece
--- /dev/null
+++ b/GFramework.SourceGenerators.Common/extensions/AttributeDataExtensions.cs
@@ -0,0 +1,47 @@
+using System;
+using Microsoft.CodeAnalysis;
+
+namespace GFramework.SourceGenerators.Common.extensions;
+
+///
+/// 提供AttributeData的扩展方法
+///
+public static class AttributeDataExtensions
+{
+ /// 特性数据对象
+ extension(AttributeData attr)
+ {
+ ///
+ /// 从特性数据中获取指定名称的命名参数值
+ ///
+ /// 期望返回的参数类型
+ /// 要查找的命名参数名称
+ /// 当找不到指定参数时返回的默认值
+ /// 找到的参数值,如果未找到或类型不匹配则返回默认值
+ public T? GetNamedArgument(string name,
+ T? defaultValue = default)
+ {
+ // 遍历所有命名参数以查找匹配的键值对
+ foreach (var kv in attr.NamedArguments)
+ {
+ if (string.Equals(kv.Key, name, StringComparison.Ordinal) && kv.Value.Value is T t)
+ return t;
+ }
+
+ return defaultValue;
+ }
+
+ ///
+ /// 获取特性构造函数的第一个参数作为字符串值
+ ///
+ /// 当没有构造函数参数或第一个参数不是字符串时返回的默认值
+ /// 构造函数第一个参数的字符串值,如果不存在则返回默认值
+ public string GetFirstCtorString(string defaultValue)
+ {
+ if (attr.ConstructorArguments.Length == 0)
+ return defaultValue;
+
+ return attr.ConstructorArguments[0].Value as string ?? defaultValue;
+ }
+ }
+}
\ No newline at end of file
diff --git a/GFramework.SourceGenerators.Common/extensions/INamedTypeSymbolExtensions.cs b/GFramework.SourceGenerators.Common/extensions/INamedTypeSymbolExtensions.cs
index 4865ea9..291efb5 100644
--- a/GFramework.SourceGenerators.Common/extensions/INamedTypeSymbolExtensions.cs
+++ b/GFramework.SourceGenerators.Common/extensions/INamedTypeSymbolExtensions.cs
@@ -1,4 +1,6 @@
using System.Collections.Generic;
+using System.Linq;
+using GFramework.SourceGenerators.Common.info;
using Microsoft.CodeAnalysis;
namespace GFramework.SourceGenerators.Common.extensions;
@@ -8,45 +10,12 @@ namespace GFramework.SourceGenerators.Common.extensions;
///
public static class INamedTypeSymbolExtensions
{
- ///
- /// 获取命名类型符号的完整类名(包括嵌套类型名称)
- ///
- /// 要获取完整类名的命名类型符号
- /// 完整的类名,格式为"外层类名.内层类名.当前类名"
- public static string GetFullClassName(this INamedTypeSymbol symbol)
- {
- var names = new Stack();
- var current = symbol;
-
- // 遍历包含类型链,将所有类型名称压入栈中
- while (current != null)
- {
- names.Push(current.Name);
- current = current.ContainingType;
- }
-
- // 将栈中的名称用点号连接,形成完整的类名
- return string.Join(".", names);
- }
-
- ///
- /// 获取命名类型符号的命名空间名称
- ///
- /// 要获取命名空间的命名类型符号
- /// 命名空间名称,如果是全局命名空间则返回null
- private static string? GetNamespace(this INamedTypeSymbol symbol)
- {
- return symbol.ContainingNamespace.IsGlobalNamespace
- ? null
- : symbol.ContainingNamespace.ToDisplayString();
- }
-
///
/// 根据类型种类解析对应的类型关键字
///
/// 要解析类型的命名类型符号
/// 对应类型的字符串表示,如"class"、"struct"或"record"
- private static string ResolveTypeKind(this INamedTypeSymbol symbol)
+ public static string ResolveTypeKind(this INamedTypeSymbol symbol)
{
return symbol.TypeKind switch
{
@@ -58,4 +27,82 @@ public static class INamedTypeSymbolExtensions
_ => "class",
};
}
+
+ ///
+ /// 解析泛型信息,包括泛型参数和约束条件
+ ///
+ /// 要解析泛型信息的命名类型符号
+ /// 包含泛型参数和约束条件的GenericInfo对象
+ public static GenericInfo ResolveGenerics(this INamedTypeSymbol symbol)
+ {
+ if (symbol.TypeParameters.Length == 0)
+ return new GenericInfo(string.Empty, []);
+
+ // 构建泛型参数列表
+ var parameters =
+ "<" + string.Join(", ", symbol.TypeParameters.Select(tp => tp.Name)) + ">";
+
+ // 构建泛型约束条件列表
+ var constraints = symbol.TypeParameters
+ .Select(BuildConstraint)
+ .Where(c => c != null)
+ .Cast()
+ .ToList();
+
+ return new GenericInfo(parameters, constraints);
+ }
+
+ ///
+ /// 构建单个类型参数的约束条件字符串
+ ///
+ /// 类型参数符号
+ /// 约束条件的字符串表示,如果没有约束则返回null
+ private static string? BuildConstraint(ITypeParameterSymbol tp)
+ {
+ var parts = new List();
+
+ if (tp.HasReferenceTypeConstraint) parts.Add("class");
+ if (tp.HasValueTypeConstraint) parts.Add("struct");
+ parts.AddRange(tp.ConstraintTypes.Select(t => t.ToDisplayString()));
+ if (tp.HasConstructorConstraint) parts.Add("new()");
+
+ return parts.Count == 0
+ ? null
+ : $"where {tp.Name} : {string.Join(", ", parts)}";
+ }
+
+ /// 要获取完整类名的命名类型符号
+ extension(INamedTypeSymbol symbol)
+ {
+ ///
+ /// 获取命名类型符号的完整类名(包括嵌套类型名称)
+ ///
+ /// 完整的类名,格式为"外层类名.内层类名.当前类名"
+ public string GetFullClassName()
+ {
+ var names = new Stack();
+ var current = symbol;
+
+ // 遍历包含类型链,将所有类型名称压入栈中
+ while (current != null)
+ {
+ names.Push(current.Name);
+ current = current.ContainingType;
+ }
+
+ // 将栈中的名称用点号连接,形成完整的类名
+ return string.Join(".", names);
+ }
+
+ ///
+ /// 获取命名类型符号的命名空间名称
+ ///
+ /// 命名空间名称,如果是全局命名空间则返回null
+ public string? GetNamespace()
+ {
+ return symbol.ContainingNamespace.IsGlobalNamespace
+ ? null
+ : symbol.ContainingNamespace.ToDisplayString();
+ }
+ }
}
\ No newline at end of file
diff --git a/GFramework.SourceGenerators.Common/info/GenericInfo.cs b/GFramework.SourceGenerators.Common/info/GenericInfo.cs
new file mode 100644
index 0000000..05869cf
--- /dev/null
+++ b/GFramework.SourceGenerators.Common/info/GenericInfo.cs
@@ -0,0 +1,13 @@
+using System.Collections.Generic;
+
+namespace GFramework.SourceGenerators.Common.info;
+
+///
+/// 表示泛型信息的数据结构
+///
+/// 泛型参数字符串
+/// 泛型约束列表
+public record struct GenericInfo(
+ string Parameters,
+ IReadOnlyList Constraints
+);
\ No newline at end of file
diff --git a/GFramework.SourceGenerators/logging/LoggerGenerator.cs b/GFramework.SourceGenerators/logging/LoggerGenerator.cs
index 577ccff..0ccb722 100644
--- a/GFramework.SourceGenerators/logging/LoggerGenerator.cs
+++ b/GFramework.SourceGenerators/logging/LoggerGenerator.cs
@@ -1,6 +1,4 @@
using System;
-using System.Collections.Generic;
-using System.Linq;
using System.Text;
using GFramework.SourceGenerators.Abstractions.logging;
using GFramework.SourceGenerators.Common.constants;
@@ -56,84 +54,42 @@ public sealed class LoggerGenerator : TypeAttributeClassGeneratorBase
INamedTypeSymbol symbol,
AttributeData attr)
{
- var ns = symbol.ContainingNamespace.IsGlobalNamespace
- ? null
- : symbol.ContainingNamespace.ToDisplayString();
-
- // 类名和嵌套类完整路径
+ var ns = symbol.GetNamespace();
var className = symbol.GetFullClassName();
+ var typeKind = symbol.ResolveTypeKind();
+ var generics = symbol.ResolveGenerics();
- // 构造函数参数解析
- var logName = className;
- if (attr.ConstructorArguments.Length > 0)
- {
- var argValue = attr.ConstructorArguments[0].Value;
- logName = 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 logName = attr.GetFirstCtorString(className);
+ var fieldName = attr.GetNamedArgument("FieldName", "_log");
+ var access = attr.GetNamedArgument("AccessModifier", "private");
+ var isStatic = attr.GetNamedArgument("IsStatic", true);
var staticKeyword = isStatic ? "static " : "";
- // 泛型参数
- var typeParams = symbol.TypeParameters.Length > 0
- ? "<" + string.Join(", ", symbol.TypeParameters.Select(tp => tp.Name)) + ">"
- : "";
-
- // 泛型约束
- var constraints = symbol.TypeParameters
- .Where(tp => tp.ConstraintTypes.Length > 0 || tp.HasReferenceTypeConstraint || tp.HasValueTypeConstraint ||
- tp.HasConstructorConstraint)
- .Select(tp =>
- {
- var parts = new List();
-
- if (tp.HasReferenceTypeConstraint) parts.Add("class");
- if (tp.HasValueTypeConstraint) parts.Add("struct");
- parts.AddRange(tp.ConstraintTypes.Select(t => t.ToDisplayString()));
- if (tp.HasConstructorConstraint) parts.Add("new()");
-
- return $"where {tp.Name} : {string.Join(", ", parts)}";
- });
-
- // 判断类型
- var typeKind = symbol.TypeKind switch
- {
- TypeKind.Class => "class",
- TypeKind.Struct => "struct",
-#if NET5_0_OR_GREATER || ROSLYN_3_7_OR_GREATER
- TypeKind.Record => "record",
-#endif
- _ => "class"
- };
-
- var sb = new StringBuilder();
- sb.AppendLine("// ");
- sb.AppendLine($"using {PathContests.CoreAbstractionsNamespace}.logging;");
- sb.AppendLine($"using {PathContests.CoreNamespace}.logging;");
+ var sb = new StringBuilder()
+ .AppendLine("// ")
+ .AppendLine($"using {PathContests.CoreAbstractionsNamespace}.logging;")
+ .AppendLine($"using {PathContests.CoreNamespace}.logging;");
if (ns is not null)
{
- sb.AppendLine($"namespace {ns};");
- sb.AppendLine();
+ sb.AppendLine()
+ .AppendLine($"namespace {ns};");
}
- // 生成 partial 类
- sb.AppendLine($"partial {typeKind} {className}{typeParams}");
- foreach (var c in constraints)
- sb.AppendLine($" {c}");
- sb.AppendLine("{");
- sb.AppendLine($" /// Auto-generated logger");
- sb.AppendLine(
- $" {access} {staticKeyword}readonly ILogger {fieldName} = LoggerFactoryResolver.Provider.CreateLogger(\"{logName}\");");
- sb.AppendLine("}");
+ sb.AppendLine()
+ .AppendLine($"partial {typeKind} {className}{generics.Parameters}");
- return sb.ToString().TrimEnd();
+ foreach (var c in generics.Constraints)
+ sb.AppendLine($" {c}");
+
+ sb.AppendLine("{")
+ .AppendLine(" /// Auto-generated logger")
+ .AppendLine(
+ $" {access} {staticKeyword}readonly ILogger {fieldName} = " +
+ $"LoggerFactoryResolver.Provider.CreateLogger(\"{logName}\");")
+ .AppendLine("}");
+
+ return sb.ToString();
}
@@ -144,9 +100,4 @@ public sealed class LoggerGenerator : TypeAttributeClassGeneratorBase
{
return $"{symbol.Name}.Logger.g.cs";
}
-
- private static object? GetNamedArg(AttributeData attr, string name)
- {
- return attr.NamedArguments.FirstOrDefault(kv => kv.Key == name).Value.Value;
- }
}
\ No newline at end of file