From 02e2e31e952c28d2ca39f2b1cb20a0933477017f Mon Sep 17 00:00:00 2001
From: GwWuYou <95328647+GeWuYou@users.noreply.github.com>
Date: Mon, 29 Dec 2025 20:06:25 +0800
Subject: [PATCH] =?UTF-8?q?feat(core):=20=E6=B7=BB=E5=8A=A0=E4=B8=8A?=
=?UTF-8?q?=E4=B8=8B=E6=96=87=E6=84=9F=E7=9F=A5=E6=89=A9=E5=B1=95=E6=96=B9?=
=?UTF-8?q?=E6=B3=95=E5=B9=B6=E5=AE=8C=E5=96=84=E6=9E=B6=E6=9E=84=E4=B8=8A?=
=?UTF-8?q?=E4=B8=8B=E6=96=87=E6=8E=A5=E5=8F=A3?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- 新增 ContextAwareExtensions 扩展类,提供便捷的上下文访问方法
- 为 IContextAware 接口添加 GetContext 方法以获取架构上下文
- 更新 ContextAwareBase 基类实现 GetContext 方法
- 改进源代码生成器的 Generate 方法参数结构
- 重构 ContextAwareGenerator 生成器实现接口方法自动实现
- 更新单元测试以验证新生成的上下文感知代码正确性
---
.../rule/IContextAware.cs | 8 +-
.../extensions/ContextAwareExtensions.cs | 166 ++++++++++++++++++
GFramework.Core/rule/ContextAwareBase.cs | 9 +
.../logging/GodotLoggerGenerator.cs | 14 +-
.../generator/AttributeClassGeneratorBase.cs | 6 +-
.../rule/ContextAwareGeneratorTests.cs | 20 ++-
.../logging/LoggerGenerator.cs | 13 +-
.../rule/ContextAwareGenerator.cs | 145 ++++++++++-----
8 files changed, 330 insertions(+), 51 deletions(-)
create mode 100644 GFramework.Core/extensions/ContextAwareExtensions.cs
diff --git a/GFramework.Core.Abstractions/rule/IContextAware.cs b/GFramework.Core.Abstractions/rule/IContextAware.cs
index 01cac5e..9fb8e6a 100644
--- a/GFramework.Core.Abstractions/rule/IContextAware.cs
+++ b/GFramework.Core.Abstractions/rule/IContextAware.cs
@@ -3,7 +3,7 @@
namespace GFramework.Core.Abstractions.rule;
///
-/// 上下文感知接口,用于为实现该接口的类提供设置架构上下文的能力
+/// 上下文感知接口,用于为实现该接口的类提供设置和获取架构上下文的能力
///
public interface IContextAware
{
@@ -12,4 +12,10 @@ public interface IContextAware
///
/// 架构上下文对象,用于提供架构级别的服务和功能访问
void SetContext(IArchitectureContext context);
+
+ ///
+ /// 获取架构上下文
+ ///
+ /// 当前的架构上下文对象
+ IArchitectureContext GetContext();
}
\ No newline at end of file
diff --git a/GFramework.Core/extensions/ContextAwareExtensions.cs b/GFramework.Core/extensions/ContextAwareExtensions.cs
new file mode 100644
index 0000000..3a5af4b
--- /dev/null
+++ b/GFramework.Core/extensions/ContextAwareExtensions.cs
@@ -0,0 +1,166 @@
+using GFramework.Core.Abstractions.command;
+using GFramework.Core.Abstractions.events;
+using GFramework.Core.Abstractions.model;
+using GFramework.Core.Abstractions.query;
+using GFramework.Core.Abstractions.rule;
+using GFramework.Core.Abstractions.system;
+using GFramework.Core.Abstractions.utility;
+
+namespace GFramework.Core.extensions;
+
+///
+/// 提供对 IContextAware 接口的扩展方法
+///
+public static class ContextAwareExtensions
+{
+ ///
+ /// 获取架构上下文中的指定系统
+ ///
+ /// 目标系统类型
+ /// 实现 IContextAware 接口的对象
+ /// 指定类型的系统实例
+ /// 当 contextAware 为 null 时抛出
+ public static TSystem? GetSystem(this IContextAware contextAware) where TSystem : class, ISystem
+ {
+ if (contextAware == null) throw new ArgumentNullException(nameof(contextAware));
+ var context = contextAware.GetContext();
+ return context.GetSystem();
+ }
+
+ ///
+ /// 获取架构上下文中的指定模型
+ ///
+ /// 目标模型类型
+ /// 实现 IContextAware 接口的对象
+ /// 指定类型的模型实例
+ /// 当 contextAware 为 null 时抛出
+ public static TModel? GetModel(this IContextAware contextAware) where TModel : class, IModel
+ {
+ if (contextAware == null) throw new ArgumentNullException(nameof(contextAware));
+ var context = contextAware.GetContext();
+ return context.GetModel();
+ }
+
+ ///
+ /// 获取架构上下文中的指定工具
+ ///
+ /// 目标工具类型
+ /// 实现 IContextAware 接口的对象
+ /// 指定类型的工具实例
+ /// 当 contextAware 为 null 时抛出
+ public static TUtility? GetUtility(this IContextAware contextAware) where TUtility : class, IUtility
+ {
+ if (contextAware == null) throw new ArgumentNullException(nameof(contextAware));
+ var context = contextAware.GetContext();
+ return context.GetUtility();
+ }
+
+ ///
+ /// 发送一个查询请求
+ ///
+ /// 查询结果类型
+ /// 实现 IContextAware 接口的对象
+ /// 要发送的查询
+ /// 查询结果
+ /// 当 contextAware 或 query 为 null 时抛出
+ public static TResult SendQuery(this IContextAware contextAware, IQuery query)
+ {
+ if (contextAware == null) throw new ArgumentNullException(nameof(contextAware));
+ if (query == null) throw new ArgumentNullException(nameof(query));
+
+ var context = contextAware.GetContext();
+ return context.SendQuery(query);
+ }
+
+ ///
+ /// 发送一个无返回结果的命令
+ ///
+ /// 实现 IContextAware 接口的对象
+ /// 要发送的命令
+ /// 当 contextAware 或 command 为 null 时抛出
+ public static void SendCommand(this IContextAware contextAware, ICommand command)
+ {
+ if (contextAware == null) throw new ArgumentNullException(nameof(contextAware));
+ if (command == null) throw new ArgumentNullException(nameof(command));
+
+ var context = contextAware.GetContext();
+ context.SendCommand(command);
+ }
+
+ ///
+ /// 发送一个带返回值的命令
+ ///
+ /// 命令执行结果类型
+ /// 实现 IContextAware 接口的对象
+ /// 要发送的命令
+ /// 命令执行结果
+ /// 当 contextAware 或 command 为 null 时抛出
+ public static TResult SendCommand(this IContextAware contextAware, ICommand command)
+ {
+ if (contextAware == null) throw new ArgumentNullException(nameof(contextAware));
+ if (command == null) throw new ArgumentNullException(nameof(command));
+
+ var context = contextAware.GetContext();
+ return context.SendCommand(command);
+ }
+
+ ///
+ /// 发送一个事件
+ ///
+ /// 事件类型
+ /// 实现 IContextAware 接口的对象
+ /// 当 contextAware 为 null 时抛出
+ public static void SendEvent(this IContextAware contextAware) where TEvent : new()
+ {
+ if (contextAware == null) throw new ArgumentNullException(nameof(contextAware));
+ var context = contextAware.GetContext();
+ context.SendEvent();
+ }
+
+ ///
+ /// 发送一个具体的事件实例
+ ///
+ /// 事件类型
+ /// 实现 IContextAware 接口的对象
+ /// 事件实例
+ /// 当 contextAware 或 e 为 null 时抛出
+ public static void SendEvent(this IContextAware contextAware, TEvent e) where TEvent : class
+ {
+ if (contextAware == null) throw new ArgumentNullException(nameof(contextAware));
+ if (e == null) throw new ArgumentNullException(nameof(e));
+
+ var context = contextAware.GetContext();
+ context.SendEvent(e);
+ }
+
+ ///
+ /// 注册事件处理器
+ ///
+ /// 事件类型
+ /// 实现 IContextAware 接口的对象
+ /// 事件处理委托
+ /// 事件注销接口
+ public static IUnRegister RegisterEvent(this IContextAware contextAware, Action handler)
+ {
+ if (contextAware == null) throw new ArgumentNullException(nameof(contextAware));
+ if (handler == null) throw new ArgumentNullException(nameof(handler));
+
+ var context = contextAware.GetContext();
+ return context.RegisterEvent(handler);
+ }
+
+ ///
+ /// 取消对某类型事件的监听
+ ///
+ /// 事件类型
+ /// 实现 IContextAware 接口的对象
+ /// 之前绑定的事件处理器
+ public static void UnRegisterEvent(this IContextAware contextAware, Action onEvent)
+ {
+ if (contextAware == null) throw new ArgumentNullException(nameof(contextAware));
+ if (onEvent == null) throw new ArgumentNullException(nameof(onEvent));
+
+ var context = contextAware.GetContext();
+ context.UnRegisterEvent(onEvent);
+ }
+}
\ No newline at end of file
diff --git a/GFramework.Core/rule/ContextAwareBase.cs b/GFramework.Core/rule/ContextAwareBase.cs
index 09a8de2..aca31d0 100644
--- a/GFramework.Core/rule/ContextAwareBase.cs
+++ b/GFramework.Core/rule/ContextAwareBase.cs
@@ -23,6 +23,15 @@ public abstract class ContextAwareBase : IContextAware
OnContextReady();
}
+ ///
+ /// 获取架构上下文
+ ///
+ /// 当前架构上下文对象
+ IArchitectureContext IContextAware.GetContext()
+ {
+ return Context;
+ }
+
///
/// 当上下文准备就绪时调用的虚方法,子类可以重写此方法来执行上下文相关的初始化逻辑
///
diff --git a/GFramework.Godot.SourceGenerators/logging/GodotLoggerGenerator.cs b/GFramework.Godot.SourceGenerators/logging/GodotLoggerGenerator.cs
index 78480da..684d3f9 100644
--- a/GFramework.Godot.SourceGenerators/logging/GodotLoggerGenerator.cs
+++ b/GFramework.Godot.SourceGenerators/logging/GodotLoggerGenerator.cs
@@ -20,12 +20,18 @@ public sealed class GodotLoggerGenerator : TypeAttributeClassGeneratorBase
protected override string AttributeShortNameWithoutSuffix => "GodotLog";
///
- /// 生成日志字段的源代码
+ /// 生成源代码
///
- /// 类符号
- /// GodotLogAttribute属性数据
+ /// 源生产上下文
+ /// 编译对象
+ /// 命名类型符号
+ /// 属性数据
/// 生成的源代码字符串
- protected override string Generate(INamedTypeSymbol symbol, AttributeData attr)
+ protected override string Generate(
+ SourceProductionContext context,
+ Compilation compilation,
+ INamedTypeSymbol symbol,
+ AttributeData attr)
{
var ns = symbol.ContainingNamespace.IsGlobalNamespace
? null
diff --git a/GFramework.SourceGenerators.Common/generator/AttributeClassGeneratorBase.cs b/GFramework.SourceGenerators.Common/generator/AttributeClassGeneratorBase.cs
index c3461d0..bc85920 100644
--- a/GFramework.SourceGenerators.Common/generator/AttributeClassGeneratorBase.cs
+++ b/GFramework.SourceGenerators.Common/generator/AttributeClassGeneratorBase.cs
@@ -109,7 +109,7 @@ public abstract class AttributeClassGeneratorBase : IIncrementalGenerator
CommonDiagnostics.Trace(context,
$"[GEN] Generating source: {hintName}");
- context.AddSource(hintName, Generate(symbol, attr));
+ context.AddSource(hintName, Generate(context, compilation, symbol, attr));
}
@@ -133,10 +133,14 @@ public abstract class AttributeClassGeneratorBase : IIncrementalGenerator
///
/// 生成源代码
///
+ /// 源生产上下文
+ /// 编译对象
/// 命名类型符号
/// 属性数据
/// 生成的源代码字符串
protected abstract string Generate(
+ SourceProductionContext context,
+ Compilation compilation,
INamedTypeSymbol symbol,
AttributeData attr);
diff --git a/GFramework.SourceGenerators.Tests/rule/ContextAwareGeneratorTests.cs b/GFramework.SourceGenerators.Tests/rule/ContextAwareGeneratorTests.cs
index 971c18d..3c36dd7 100644
--- a/GFramework.SourceGenerators.Tests/rule/ContextAwareGeneratorTests.cs
+++ b/GFramework.SourceGenerators.Tests/rule/ContextAwareGeneratorTests.cs
@@ -40,6 +40,8 @@ public class ContextAwareGeneratorTests
{
void SetContext(
GFramework.Core.Abstractions.architecture.IArchitectureContext context);
+
+ GFramework.Core.Abstractions.architecture.IArchitectureContext GetContext();
}
}
@@ -62,11 +64,17 @@ public class ContextAwareGeneratorTests
///
protected GFramework.Core.Abstractions.architecture.IArchitectureContext Context { get; private set; } = null!;
- void GFramework.Core.Abstractions.rule.IContextAware.SetContext(
- GFramework.Core.Abstractions.architecture.IArchitectureContext context)
+ void global::GFramework.Core.Abstractions.rule.IContextAware.SetContext(
+ global::GFramework.Core.Abstractions.architecture.IArchitectureContext context)
{
Context = context;
}
+
+ global::GFramework.Core.Abstractions.architecture.IArchitectureContext
+ global::GFramework.Core.Abstractions.rule.IContextAware.GetContext()
+ {
+ return Context;
+ }
}
""";
@@ -113,6 +121,8 @@ public class ContextAwareGeneratorTests
{
void SetContext(
GFramework.Core.Abstractions.architecture.IArchitectureContext context);
+
+ GFramework.Core.Abstractions.architecture.IArchitectureContext GetContext();
}
}
@@ -140,6 +150,12 @@ public class ContextAwareGeneratorTests
{
Context = context;
}
+
+ GFramework.Core.Abstractions.architecture.IArchitectureContext
+ GFramework.Core.Abstractions.rule.IContextAware.GetContext()
+ {
+ return Context;
+ }
}
""";
diff --git a/GFramework.SourceGenerators/logging/LoggerGenerator.cs b/GFramework.SourceGenerators/logging/LoggerGenerator.cs
index f8c1292..add02af 100644
--- a/GFramework.SourceGenerators/logging/LoggerGenerator.cs
+++ b/GFramework.SourceGenerators/logging/LoggerGenerator.cs
@@ -41,9 +41,18 @@ public sealed class LoggerGenerator : TypeAttributeClassGeneratorBase
}
///
- /// 生成 Logger 字段的代码
+ /// 生成源代码
///
- protected override string Generate(INamedTypeSymbol symbol, AttributeData attr)
+ /// 源生产上下文
+ /// 编译对象
+ /// 命名类型符号
+ /// 属性数据
+ /// 生成的源代码字符串
+ protected override string Generate(
+ SourceProductionContext context,
+ Compilation compilation,
+ INamedTypeSymbol symbol,
+ AttributeData attr)
{
var ns = symbol.ContainingNamespace.IsGlobalNamespace
? null
diff --git a/GFramework.SourceGenerators/rule/ContextAwareGenerator.cs b/GFramework.SourceGenerators/rule/ContextAwareGenerator.cs
index b8fd5a7..5d825b4 100644
--- a/GFramework.SourceGenerators/rule/ContextAwareGenerator.cs
+++ b/GFramework.SourceGenerators/rule/ContextAwareGenerator.cs
@@ -11,23 +11,11 @@ namespace GFramework.SourceGenerators.rule;
[Generator]
public sealed class ContextAwareGenerator : MetadataAttributeClassGeneratorBase
{
- ///
- /// 获取属性元数据的完整名称,用于标识ContextAwareAttribute的完全限定名
- ///
- /// 返回ContextAwareAttribute的完全限定名字符串
protected override string AttributeMetadataName =>
$"{PathContests.SourceGeneratorsAbstractionsPath}.rule.ContextAwareAttribute";
- ///
- /// 仅用于 Syntax 粗筛选
- ///
- /// 返回属性的简短名称,不包含后缀
protected override string AttributeShortNameWithoutSuffix => "ContextAware";
-
- ///
- /// 额外语义校验:必须实现 IContextAware
- ///
protected override bool ValidateSymbol(
SourceProductionContext context,
Compilation compilation,
@@ -35,9 +23,8 @@ public sealed class ContextAwareGenerator : MetadataAttributeClassGeneratorBase
INamedTypeSymbol symbol,
AttributeData attr)
{
- var iContextAware = compilation
- .GetTypeByMetadataName(
- $"{PathContests.CoreAbstractionsNamespace}.rule.IContextAware");
+ var iContextAware = compilation.GetTypeByMetadataName(
+ $"{PathContests.CoreAbstractionsNamespace}.rule.IContextAware");
if (iContextAware is null)
{
@@ -45,7 +32,6 @@ public sealed class ContextAwareGenerator : MetadataAttributeClassGeneratorBase
ContextAwareDiagnostic.ClassMustImplementIContextAware,
syntax.Identifier.GetLocation(),
symbol.Name));
-
return false;
}
@@ -56,24 +42,31 @@ public sealed class ContextAwareGenerator : MetadataAttributeClassGeneratorBase
ContextAwareDiagnostic.ClassMustImplementIContextAware,
syntax.Identifier.GetLocation(),
symbol.Name));
-
return false;
}
return true;
}
-
///
- /// 生成源码
+ /// 生成源代码
///
+ /// 源生产上下文
+ /// 编译对象
+ /// 命名类型符号
+ /// 属性数据
+ /// 生成的源代码字符串
protected override string Generate(
+ SourceProductionContext context,
+ Compilation compilation,
INamedTypeSymbol symbol,
AttributeData attr)
{
var ns = symbol.ContainingNamespace.IsGlobalNamespace
? null
: symbol.ContainingNamespace.ToDisplayString();
+ var iContextAware = compilation.GetTypeByMetadataName(
+ $"{PathContests.CoreAbstractionsNamespace}.rule.IContextAware");
var sb = new StringBuilder();
sb.AppendLine("// ");
@@ -89,36 +82,106 @@ public sealed class ContextAwareGenerator : MetadataAttributeClassGeneratorBase
sb.AppendLine($"partial class {symbol.Name}");
sb.AppendLine("{");
- // 属性
+ GenerateContextProperty(sb);
+ GenerateInterfaceImplementations(sb, iContextAware!);
+
+ sb.AppendLine("}");
+ return sb.ToString().TrimEnd();
+ }
+
+ protected override string GetHintName(INamedTypeSymbol symbol)
+ => $"{symbol.Name}.ContextAware.g.cs";
+
+ // =========================
+ // 生成 Context 属性
+ // =========================
+ private static void GenerateContextProperty(StringBuilder sb)
+ {
sb.AppendLine(" /// ");
sb.AppendLine(" /// 自动注入的架构上下文");
sb.AppendLine(" /// ");
sb.AppendLine(
$" protected {PathContests.CoreAbstractionsNamespace}.architecture.IArchitectureContext Context {{ get; private set; }} = null!;");
sb.AppendLine();
-
- // 方法
- sb.AppendLine(
- $" void {PathContests.CoreAbstractionsNamespace}.rule.IContextAware.SetContext(");
- sb.AppendLine(
- $" {PathContests.CoreAbstractionsNamespace}.architecture.IArchitectureContext context)");
- sb.AppendLine(" {");
- sb.AppendLine(" Context = context;");
- sb.AppendLine(" }");
-
- sb.AppendLine("}");
-
- return sb.ToString().TrimEnd();
}
-
- ///
- /// 自定义生成文件名
- ///
- protected override string GetHintName(INamedTypeSymbol symbol)
+ // =========================
+ // 自动实现接口方法
+ // =========================
+ private static void GenerateInterfaceImplementations(
+ StringBuilder sb,
+ INamedTypeSymbol interfaceSymbol)
{
- // 包含命名空间和生成器类名路径
- return
- $"{symbol.Name}.ContextAware.g.cs";
+ var interfaceFullName = interfaceSymbol.ToDisplayString(
+ SymbolDisplayFormat.FullyQualifiedFormat);
+
+ foreach (var member in interfaceSymbol.GetMembers().OfType())
+ {
+ if (member.MethodKind != MethodKind.Ordinary)
+ continue;
+
+ GenerateMethod(sb, interfaceFullName, member);
+ sb.AppendLine();
+ }
+ }
+
+ private static void GenerateMethod(
+ StringBuilder sb,
+ string interfaceFullName,
+ IMethodSymbol method)
+ {
+ var returnType = method.ReturnType.ToDisplayString(
+ SymbolDisplayFormat.FullyQualifiedFormat);
+
+ var parameters = string.Join(", ",
+ method.Parameters.Select(p =>
+ $"{p.Type.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat)} {p.Name}"));
+
+ sb.AppendLine(
+ $" {returnType} {interfaceFullName}.{method.Name}({parameters})");
+
+ sb.AppendLine(" {");
+ GenerateMethodBody(sb, method);
+ sb.AppendLine(" }");
+ }
+
+ // =========================
+ // 方法语义策略
+ // =========================
+ private static void GenerateMethodBody(
+ StringBuilder sb,
+ IMethodSymbol method)
+ {
+ switch (method.Name)
+ {
+ case "SetContext":
+ sb.AppendLine(" Context = context;");
+ break;
+
+ case "GetContext":
+ sb.AppendLine(" return Context;");
+ break;
+
+ default:
+ GenerateFallbackBody(sb, method);
+ break;
+ }
+ }
+
+ private static void GenerateFallbackBody(
+ StringBuilder sb,
+ IMethodSymbol method)
+ {
+ if (method.ReturnsVoid)
+ {
+ sb.AppendLine(" // no-op");
+ }
+ else
+ {
+ sb.AppendLine(
+ $" throw new System.NotImplementedException(");
+ sb.AppendLine(
+ $" \"Method '{method.Name}' is not supported by ContextAwareGenerator.\");");
+ }
}
}
\ No newline at end of file