using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; using System.Collections.Generic; using System.Linq; using System.Text; using Analyzer; [Generator] public class EventInterfaceGenerator : ISourceGenerator { public void Initialize(GeneratorInitializationContext context) { // 可以在这里进行初始化 } public void Execute(GeneratorExecutionContext context) { // 获取当前语法树 var syntaxTrees = context.Compilation.SyntaxTrees; List classNameList = new List(); foreach (var tree in syntaxTrees) { var root = tree.GetRoot(); var interfaces = root.DescendantNodes() .OfType() .Where(i => i.AttributeLists.Count > 0 && i.AttributeLists .Any(a => a.Attributes .Any(attr => attr.Name.ToString() == $"{Definition.EventInterface}"))); foreach (var interfaceNode in interfaces) { var interfaceName = interfaceNode.Identifier.ToString(); var fullName = interfaceNode.SyntaxTree.GetRoot() .DescendantNodes() .OfType() .Select(ns => ns.Name.ToString()) .Concat(new[] { interfaceName }) .Aggregate((a, b) => a + "." + b); var eventClassName = $"{interfaceName}_Event"; var eventClassCode = GenerateEventClass(interfaceName, eventClassName, interfaceNode); context.AddSource($"{eventClassName}.g.cs", eventClassCode); // 生成实现类 var implementationClassCode = GenerateImplementationClass(fullName, interfaceName, interfaceNode,context); context.AddSource($"{interfaceName}_Gen.g.cs", implementationClassCode); classNameList.Add($"{interfaceName}_Gen"); } } string uniqueFileName = $"GameEventHelper.g.cs"; context.AddSource(uniqueFileName, GenerateGameEventHelper(classNameList)); } private string GenerateGameEventHelper(List classNameList) { var sb = new StringBuilder(); sb.AppendLine($"//------------------------------------------------------------------------------"); sb.AppendLine($"// "); sb.AppendLine($"// This code was generated by autoBindTool."); sb.AppendLine($"// Changes to this file may cause incorrect behavior and will be lost if"); sb.AppendLine($"// the code is regenerated."); sb.AppendLine($"// "); sb.AppendLine($"//------------------------------------------------------------------------------"); sb.AppendLine(); sb.AppendLine($"using UnityEngine;"); sb.AppendLine($"using UnityEngine.UI;"); sb.AppendLine($"using {Definition.FrameworkNameSpace};"); sb.AppendLine(); sb.AppendLine($"namespace {Definition.NameSpace}"); sb.AppendLine($"{{"); sb.AppendLine($" public static class GameEventHelper"); sb.AppendLine(" {"); sb.AppendLine($" public static void Init()"); sb.AppendLine(" {"); foreach (var className in classNameList) { sb.AppendLine($" var m_{className} = new {className}(GameEvent.EventMgr.GetDispatcher());"); } sb.AppendLine(" }"); sb.AppendLine(" }"); sb.AppendLine("}"); return sb.ToString(); } private string GenerateEventClass(string interfaceName, string className, InterfaceDeclarationSyntax interfaceNode) { var methods = interfaceNode.Members.OfType(); var sb = new StringBuilder(); sb.AppendLine($"//------------------------------------------------------------------------------"); sb.AppendLine($"// "); sb.AppendLine($"// This code was generated by autoBindTool."); sb.AppendLine($"// Changes to this file may cause incorrect behavior and will be lost if"); sb.AppendLine($"// the code is regenerated."); sb.AppendLine($"// "); sb.AppendLine($"//------------------------------------------------------------------------------"); sb.AppendLine(); sb.AppendLine($"using UnityEngine;"); sb.AppendLine($"using UnityEngine.UI;"); sb.AppendLine($"using {Definition.FrameworkNameSpace};"); sb.AppendLine(); sb.AppendLine($"namespace {Definition.NameSpace}"); sb.AppendLine("{"); sb.AppendLine($" public partial class {className}"); sb.AppendLine(" {"); foreach (var method in methods) { var methodName = method.Identifier.ToString(); var parameters = string.Join(", ", method.ParameterList.Parameters.Select(p => $"{p.Type} {p.Identifier}")); sb.AppendLine($" public static readonly int {methodName} = {Definition.StringToHash}(\"{className}.{methodName}\");"); } sb.AppendLine(" }"); sb.AppendLine("}"); return sb.ToString(); } private string GenerateImplementationClass(string interfaceFullName, string interfaceName, InterfaceDeclarationSyntax interfaceNode,GeneratorExecutionContext context) { var semanticModel = context.Compilation.GetSemanticModel(interfaceNode.SyntaxTree); var sb = new StringBuilder(); sb.AppendLine($"//------------------------------------------------------------------------------"); sb.AppendLine($"// "); sb.AppendLine($"// This code was generated by autoBindTool."); sb.AppendLine($"// Changes to this file may cause incorrect behavior and will be lost if"); sb.AppendLine($"// the code is regenerated."); sb.AppendLine($"// "); sb.AppendLine($"//------------------------------------------------------------------------------"); sb.AppendLine(); sb.AppendLine($"using UnityEngine;"); sb.AppendLine($"using UnityEngine.UI;"); sb.AppendLine($"using {Definition.FrameworkNameSpace};"); sb.AppendLine(); sb.AppendLine($"namespace {Definition.NameSpace}"); sb.AppendLine($"{{"); sb.AppendLine($" public partial class {interfaceName}_Gen : {interfaceName}"); sb.AppendLine(" {"); sb.AppendLine(" private EventDispatcher _dispatcher;"); sb.AppendLine($" public {interfaceName}_Gen(EventDispatcher dispatcher)"); sb.AppendLine(" {"); sb.AppendLine(" _dispatcher = dispatcher;"); sb.AppendLine($" GameEvent.EventMgr.RegWrapInterface(\"{interfaceFullName}\", this);"); sb.AppendLine(" }"); foreach (var method in interfaceNode.Members.OfType()) { var methodName = method.Identifier.ToString(); var parameters = GenerateParameters(method, semanticModel); sb.AppendLine($" public void {methodName}({parameters})"); sb.AppendLine(" {"); if (method.ParameterList.Parameters.Count > 0) { var paramNames = string.Join(", ", method.ParameterList.Parameters.Select(p => p.Identifier.ToString())); sb.AppendLine($" _dispatcher.Send({interfaceName}_Event.{methodName}, {paramNames});"); } else { sb.AppendLine($" _dispatcher.Send({interfaceName}_Event.{methodName});"); } sb.AppendLine(" }"); } sb.AppendLine(" }"); sb.AppendLine("}"); return sb.ToString(); } private string GenerateParameters(MethodDeclarationSyntax method, SemanticModel semanticModel) { return string.Join(", ", method.ParameterList.Parameters.Select(p => { var typeSymbol = semanticModel.GetTypeInfo(p.Type).Type; return typeSymbol != null ? $"{typeSymbol.ToDisplayString()} {p.Identifier}" : $"{p.Type} {p.Identifier}"; })); } }