GFramework/GFramework.SourceGenerators/rule/ContextAwareGenerator.cs
GeWuYou 0ed8edf015 refactor(context): 重构上下文管理实现
- 引入 IArchitectureContextProvider 接口解耦上下文获取逻辑
- 创建 GameContextProvider 作为默认上下文提供者
- 添加 ScopedContextProvider 支持多架构实例场景
- 修改源代码生成器使用上下文提供者模式
- 增加 SetContextProvider 方法支持测试和多架构场景
- 添加 RegistryInitializationHookBase 简化注册表初始化逻辑
2026-03-02 12:42:09 +08:00

246 lines
8.6 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using System.Text;
using GFramework.SourceGenerators.Common.constants;
using GFramework.SourceGenerators.Common.diagnostics;
using GFramework.SourceGenerators.Common.generator;
using GFramework.SourceGenerators.diagnostics;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
namespace GFramework.SourceGenerators.rule;
/// <summary>
/// 上下文感知生成器用于为标记了ContextAware特性的类自动生成IContextAware接口实现
/// </summary>
[Generator]
public sealed class ContextAwareGenerator : MetadataAttributeClassGeneratorBase
{
/// <summary>
/// 获取特性的元数据名称
/// </summary>
protected override string AttributeMetadataName =>
$"{PathContests.SourceGeneratorsAbstractionsPath}.rule.ContextAwareAttribute";
/// <summary>
/// 获取特性的短名称(不包含后缀)
/// </summary>
protected override string AttributeShortNameWithoutSuffix => "ContextAware";
/// <summary>
/// 验证符号是否符合生成条件
/// </summary>
/// <param name="context">源生产上下文</param>
/// <param name="compilation">编译对象</param>
/// <param name="syntax">类声明语法节点</param>
/// <param name="symbol">命名类型符号</param>
/// <param name="attr">特性数据</param>
/// <returns>验证是否通过</returns>
protected override bool ValidateSymbol(
SourceProductionContext context,
Compilation compilation,
ClassDeclarationSyntax syntax,
INamedTypeSymbol symbol,
AttributeData attr)
{
// 1. 必须是 partial
if (!syntax.Modifiers.Any(SyntaxKind.PartialKeyword))
{
context.ReportDiagnostic(Diagnostic.Create(
CommonDiagnostics.ClassMustBePartial,
syntax.Identifier.GetLocation(),
symbol.Name));
return false;
}
// 2. 必须是 class
if (symbol.TypeKind != TypeKind.Class)
{
context.ReportDiagnostic(Diagnostic.Create(
ContextAwareDiagnostic.ContextAwareOnlyForClass,
syntax.Identifier.GetLocation(),
symbol.Name));
return false;
}
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 iContextAware = compilation.GetTypeByMetadataName(
$"{PathContests.CoreAbstractionsNamespace}.rule.IContextAware")!;
var sb = new StringBuilder();
sb.AppendLine("// <auto-generated/>");
sb.AppendLine("#nullable enable");
sb.AppendLine();
if (ns is not null)
{
sb.AppendLine($"namespace {ns};");
sb.AppendLine();
}
var interfaceName = iContextAware.ToDisplayString(
SymbolDisplayFormat.FullyQualifiedFormat);
sb.AppendLine($"partial class {symbol.Name} : {interfaceName}");
sb.AppendLine("{");
GenerateContextProperty(sb);
GenerateInterfaceImplementations(sb, iContextAware);
sb.AppendLine("}");
return sb.ToString().TrimEnd();
}
/// <summary>
/// 获取生成文件的提示名称
/// </summary>
/// <param name="symbol">命名类型符号</param>
/// <returns>生成文件的提示名称</returns>
protected override string GetHintName(INamedTypeSymbol symbol)
{
return $"{symbol.Name}.ContextAware.g.cs";
}
// =========================
// Context 属性(使用 IArchitectureContextProvider
// =========================
/// <summary>
/// 生成Context属性
/// </summary>
/// <param name="sb">字符串构建器</param>
private static void GenerateContextProperty(StringBuilder sb)
{
sb.AppendLine(" private global::GFramework.Core.Abstractions.architecture.IArchitectureContext? _context;");
sb.AppendLine(
" private static global::GFramework.Core.Abstractions.architecture.IArchitectureContextProvider? _contextProvider;");
sb.AppendLine();
sb.AppendLine(" /// <summary>");
sb.AppendLine(" /// 自动获取的架构上下文(懒加载,默认使用 GameContextProvider");
sb.AppendLine(" /// </summary>");
sb.AppendLine(" protected global::GFramework.Core.Abstractions.architecture.IArchitectureContext Context");
sb.AppendLine(" {");
sb.AppendLine(" get");
sb.AppendLine(" {");
sb.AppendLine(" if (_context == null)");
sb.AppendLine(" {");
sb.AppendLine(
" _contextProvider ??= new global::GFramework.Core.architecture.GameContextProvider();");
sb.AppendLine(" _context = _contextProvider.GetContext();");
sb.AppendLine(" }");
sb.AppendLine();
sb.AppendLine(" return _context;");
sb.AppendLine(" }");
sb.AppendLine(" }");
sb.AppendLine();
sb.AppendLine(" /// <summary>");
sb.AppendLine(" /// 配置上下文提供者(用于测试或多架构场景)");
sb.AppendLine(" /// </summary>");
sb.AppendLine(" /// <param name=\"provider\">上下文提供者实例</param>");
sb.AppendLine(
" public static void SetContextProvider(global::GFramework.Core.Abstractions.architecture.IArchitectureContextProvider provider)");
sb.AppendLine(" {");
sb.AppendLine(" _contextProvider = provider;");
sb.AppendLine(" }");
sb.AppendLine();
}
// =========================
// 显式接口实现(使用 global::
// =========================
/// <summary>
/// 生成接口实现
/// </summary>
/// <param name="sb">字符串构建器</param>
/// <param name="interfaceSymbol">接口符号</param>
private static void GenerateInterfaceImplementations(
StringBuilder sb,
INamedTypeSymbol interfaceSymbol)
{
var interfaceName = interfaceSymbol.ToDisplayString(
SymbolDisplayFormat.FullyQualifiedFormat);
foreach (var method in interfaceSymbol.GetMembers().OfType<IMethodSymbol>())
{
if (method.MethodKind != MethodKind.Ordinary)
continue;
GenerateMethod(sb, interfaceName, method);
sb.AppendLine();
}
}
/// <summary>
/// 生成方法实现
/// </summary>
/// <param name="sb">字符串构建器</param>
/// <param name="interfaceName">接口名称</param>
/// <param name="method">方法符号</param>
private static void GenerateMethod(
StringBuilder sb,
string interfaceName,
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} {interfaceName}.{method.Name}({parameters})");
sb.AppendLine(" {");
GenerateMethodBody(sb, method);
sb.AppendLine(" }");
}
/// <summary>
/// 生成方法体
/// </summary>
/// <param name="sb">字符串构建器</param>
/// <param name="method">方法符号</param>
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:
if (!method.ReturnsVoid)
sb.AppendLine(
$" throw new System.NotImplementedException(\"Method '{method.Name}' is not supported.\");");
break;
}
}
}