using GFramework.SourceGenerators.Common.Constants; namespace GFramework.Cqrs.SourceGenerators.Cqrs; /// /// 为当前编译程序集生成 CQRS 处理器注册器,以减少运行时的程序集反射扫描成本。 /// [Generator] public sealed partial class CqrsHandlerRegistryGenerator : IIncrementalGenerator { private const string CqrsContractsNamespace = $"{PathContests.CqrsAbstractionsNamespace}.Cqrs"; private const string CqrsRuntimeNamespace = PathContests.CqrsNamespace; private const string LoggingNamespace = $"{PathContests.CoreAbstractionsNamespace}.Logging"; private const string IRequestHandlerMetadataName = $"{CqrsContractsNamespace}.IRequestHandler`2"; private const string INotificationHandlerMetadataName = $"{CqrsContractsNamespace}.INotificationHandler`1"; private const string IStreamRequestHandlerMetadataName = $"{CqrsContractsNamespace}.IStreamRequestHandler`2"; private const string ICqrsHandlerRegistryMetadataName = $"{CqrsRuntimeNamespace}.ICqrsHandlerRegistry"; private const string ICqrsRequestInvokerProviderMetadataName = $"{CqrsRuntimeNamespace}.ICqrsRequestInvokerProvider"; private const string IEnumeratesCqrsRequestInvokerDescriptorsMetadataName = $"{CqrsRuntimeNamespace}.IEnumeratesCqrsRequestInvokerDescriptors"; private const string CqrsRequestInvokerDescriptorMetadataName = $"{CqrsRuntimeNamespace}.CqrsRequestInvokerDescriptor"; private const string CqrsRequestInvokerDescriptorEntryMetadataName = $"{CqrsRuntimeNamespace}.CqrsRequestInvokerDescriptorEntry"; private const string CqrsHandlerRegistryAttributeMetadataName = $"{CqrsRuntimeNamespace}.CqrsHandlerRegistryAttribute"; private const string CqrsReflectionFallbackAttributeMetadataName = $"{CqrsRuntimeNamespace}.CqrsReflectionFallbackAttribute"; private const string ILoggerMetadataName = $"{LoggingNamespace}.ILogger"; private const string IServiceCollectionMetadataName = "Microsoft.Extensions.DependencyInjection.IServiceCollection"; private const string GeneratedNamespace = "GFramework.Generated.Cqrs"; private const string GeneratedTypeName = "__GFrameworkGeneratedCqrsHandlerRegistry"; private const string HintName = "CqrsHandlerRegistry.g.cs"; private static readonly DiagnosticDescriptor MissingReflectionFallbackContractDiagnostic = new( "GF_Cqrs_001", "Cannot emit CQRS registry without reflection fallback contract", "Cannot generate CQRS handler registry because fallback metadata is required for handler(s): {0}, but runtime contract '{1}' is unavailable", "GFramework.Cqrs.SourceGenerators", DiagnosticSeverity.Error, true); /// public void Initialize(IncrementalGeneratorInitializationContext context) { var generationEnvironment = context.CompilationProvider .Select(static (compilation, _) => CreateGenerationEnvironment(compilation)); // Restrict semantic analysis to type declarations that can actually contribute implemented interfaces. var handlerCandidates = context.SyntaxProvider.CreateSyntaxProvider( static (node, _) => IsHandlerCandidate(node), static (syntaxContext, _) => TransformHandlerCandidate(syntaxContext)) .Where(static candidate => candidate is not null) .Collect(); context.RegisterSourceOutput( generationEnvironment.Combine(handlerCandidates), static (productionContext, pair) => Execute(productionContext, pair.Left, pair.Right)); } private static GenerationEnvironment CreateGenerationEnvironment(Compilation compilation) { var reflectionFallbackAttributeType = compilation.GetTypeByMetadataName(CqrsReflectionFallbackAttributeMetadataName); var generationEnabled = compilation.GetTypeByMetadataName(IRequestHandlerMetadataName) is not null && compilation.GetTypeByMetadataName(INotificationHandlerMetadataName) is not null && compilation.GetTypeByMetadataName(IStreamRequestHandlerMetadataName) is not null && compilation.GetTypeByMetadataName(ICqrsHandlerRegistryMetadataName) is not null && compilation.GetTypeByMetadataName( CqrsHandlerRegistryAttributeMetadataName) is not null && compilation.GetTypeByMetadataName(ILoggerMetadataName) is not null && compilation.GetTypeByMetadataName(IServiceCollectionMetadataName) is not null; var supportsRequestInvokerProvider = compilation.GetTypeByMetadataName(ICqrsRequestInvokerProviderMetadataName) is not null && compilation.GetTypeByMetadataName(IEnumeratesCqrsRequestInvokerDescriptorsMetadataName) is not null && compilation.GetTypeByMetadataName(CqrsRequestInvokerDescriptorMetadataName) is not null && compilation.GetTypeByMetadataName(CqrsRequestInvokerDescriptorEntryMetadataName) is not null; var stringType = compilation.GetSpecialType(SpecialType.System_String); var typeType = compilation.GetTypeByMetadataName("System.Type"); var supportsNamedReflectionFallbackTypes = reflectionFallbackAttributeType is not null && HasParamsArrayConstructor( reflectionFallbackAttributeType, stringType); var supportsDirectReflectionFallbackTypes = reflectionFallbackAttributeType is not null && typeType is not null && HasParamsArrayConstructor( reflectionFallbackAttributeType, typeType); var supportsMultipleReflectionFallbackAttributes = reflectionFallbackAttributeType is not null && SupportsMultipleAttributeInstances( reflectionFallbackAttributeType); return new GenerationEnvironment( generationEnabled, supportsNamedReflectionFallbackTypes, supportsDirectReflectionFallbackTypes, supportsMultipleReflectionFallbackAttributes, supportsRequestInvokerProvider); } private static bool IsHandlerCandidate(SyntaxNode node) { return node is TypeDeclarationSyntax { BaseList.Types.Count: > 0 }; } private static HandlerCandidateAnalysis? TransformHandlerCandidate(GeneratorSyntaxContext context) { if (context.Node is not TypeDeclarationSyntax typeDeclaration) return null; if (context.SemanticModel.GetDeclaredSymbol(typeDeclaration) is not INamedTypeSymbol type) return null; if (!IsConcreteHandlerType(type)) return null; var handlerInterfaces = GetSupportedHandlerInterfaces(type); if (handlerInterfaces.IsDefaultOrEmpty) return null; return CreateHandlerCandidateAnalysis(context.SemanticModel.Compilation, type, handlerInterfaces); } /// /// 收集当前实现类型已经关闭的 CQRS handler 接口,并按稳定显示名排序以保证生成输出可重复。 /// /// 当前语义模型发现的具体 handler 实现类型。 /// 可由 CQRS 注册器生成器处理的 handler 接口集合。 private static ImmutableArray GetSupportedHandlerInterfaces(INamedTypeSymbol type) { return type.AllInterfaces .Where(IsSupportedHandlerInterface) .OrderBy(GetTypeSortKey, StringComparer.Ordinal) .ToImmutableArray(); } /// /// 将单个实现类型的 handler 接口拆分为直接注册、实现类型反射注册、精确反射注册和兜底 fallback 四类结果。 /// /// 当前生成轮次的编译上下文,用于判断类型可访问性。 /// 需要分析的 handler 实现类型。 /// 该实现类型声明的受支持 CQRS handler 接口。 /// 供最终生成阶段消费的 handler 候选分析结果。 private static HandlerCandidateAnalysis CreateHandlerCandidateAnalysis( Compilation compilation, INamedTypeSymbol type, ImmutableArray handlerInterfaces) { var implementationTypeDisplayName = type.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat); var implementationLogName = GetLogDisplayName(type); var canReferenceImplementation = CanReferenceFromGeneratedRegistry(compilation, type); var registrations = ImmutableArray.CreateBuilder(handlerInterfaces.Length); var reflectedImplementationRegistrations = ImmutableArray.CreateBuilder(handlerInterfaces.Length); var preciseReflectedRegistrations = ImmutableArray.CreateBuilder(handlerInterfaces.Length); string? reflectionFallbackHandlerTypeDisplayName = null; string? reflectionFallbackHandlerTypeMetadataName = null; foreach (var handlerInterface in handlerInterfaces) { if (TryAddStaticHandlerRegistration( compilation, handlerInterface, canReferenceImplementation, implementationTypeDisplayName, implementationLogName, registrations, reflectedImplementationRegistrations, preciseReflectedRegistrations)) { continue; } // Concrete closed handler contracts should now always map to either direct registrations, // reflected implementation registrations, or precise runtime type references. // If a future Roslyn type shape still slips through this net, keep the generator conservative: // preserve the static registrations we do understand, and let the runtime recover the remaining // interfaces via the existing assembly-level targeted reflection fallback contract. if (canReferenceImplementation) reflectionFallbackHandlerTypeDisplayName ??= implementationTypeDisplayName; reflectionFallbackHandlerTypeMetadataName ??= GetReflectionTypeMetadataName(type); } return new HandlerCandidateAnalysis( implementationTypeDisplayName, implementationLogName, registrations.ToImmutable(), reflectedImplementationRegistrations.ToImmutable(), preciseReflectedRegistrations.ToImmutable(), canReferenceImplementation ? null : GetReflectionTypeMetadataName(type), reflectionFallbackHandlerTypeDisplayName, reflectionFallbackHandlerTypeMetadataName); } /// /// 尝试为单个 handler 接口选择无需程序集级 fallback 的注册表示。 /// /// 当前生成轮次的编译上下文。 /// 正在分类的关闭 handler 接口。 /// 生成代码是否可直接引用实现类型。 /// 实现类型在生成源码中的全限定显示名。 /// 实现类型用于日志输出的稳定显示名。 /// 直接类型注册集合。 /// 实现类型需要反射解析、接口可直接引用的注册集合。 /// 接口类型需要运行时精确构造的注册集合。 /// /// 当当前接口已经被添加到某个静态注册集合时返回 ;否则调用方应记录 reflection fallback 元数据。 /// private static bool TryAddStaticHandlerRegistration( Compilation compilation, INamedTypeSymbol handlerInterface, bool canReferenceImplementation, string implementationTypeDisplayName, string implementationLogName, ImmutableArray.Builder registrations, ImmutableArray.Builder reflectedImplementationRegistrations, ImmutableArray.Builder preciseReflectedRegistrations) { var canReferenceHandlerInterface = CanReferenceFromGeneratedRegistry(compilation, handlerInterface); if (canReferenceImplementation && canReferenceHandlerInterface) { registrations.Add(new HandlerRegistrationSpec( handlerInterface.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat), implementationTypeDisplayName, GetLogDisplayName(handlerInterface), implementationLogName, TryCreateRequestInvokerRegistrationSpec(handlerInterface, out var requestInvokerRegistration) ? requestInvokerRegistration : null)); return true; } if (!canReferenceImplementation && canReferenceHandlerInterface) { reflectedImplementationRegistrations.Add(new ReflectedImplementationRegistrationSpec( handlerInterface.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat), GetLogDisplayName(handlerInterface))); return true; } if (!TryCreatePreciseReflectedRegistration(compilation, handlerInterface, out var preciseReflectedRegistration)) return false; preciseReflectedRegistrations.Add(preciseReflectedRegistration); return true; } /// /// 当当前直接注册项属于请求处理器时,提取 request invoker provider 所需的请求/响应类型显示名。 /// private static bool TryCreateRequestInvokerRegistrationSpec( INamedTypeSymbol handlerInterface, out RequestInvokerRegistrationSpec requestInvokerRegistration) { if (!string.Equals( handlerInterface.OriginalDefinition.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat), $"global::{CqrsContractsNamespace}.IRequestHandler", StringComparison.Ordinal)) { requestInvokerRegistration = default; return false; } if (handlerInterface.TypeArguments.Length != 2) { requestInvokerRegistration = default; return false; } requestInvokerRegistration = new RequestInvokerRegistrationSpec( handlerInterface.TypeArguments[0].ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat), handlerInterface.TypeArguments[1].ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat)); return true; } /// /// 执行 CQRS handler registry 生成管线的最终发射阶段,负责将候选 handler 分析结果汇总为单个 /// CqrsHandlerRegistry.g.cs,并在需要时附带程序集级 reflection fallback 元数据。 /// /// 用于报告诊断并发射生成源码的源生产上下文。 /// /// 当前编译轮次可用的 runtime 合同快照。 /// 只有当 CQRS 注册器生成所需的基础契约齐备时,才允许继续生成;当存在 /// CqrsReflectionFallbackAttribute 时,才允许输出依赖 fallback 元数据恢复的注册结果。 /// /// /// 来自语法和语义分析阶段的 handler 候选结果。 /// 集合中可能包含 占位项,且同一实现类型可能因 partial 声明重复出现,后续会统一去重并聚合。 /// /// /// /// 该方法负责发射两类生成结果:注册器类型本体,以及在静态类型信息不足时用于运行时补全注册的程序集级 /// CqrsReflectionFallbackAttribute 元数据。生成这些结果的目标是把可静态确定的 handler 注册尽量前移到编译期, /// 从而减少运行时程序集扫描成本,同时保留对少数复杂类型形态的兼容回退路径。 /// /// /// 该阶段依赖两个语义前提:一是 runtime 已提供 CQRS 注册器生成所需的基础合同;二是只要存在任何 handler /// 需要通过 reflection fallback 恢复,就必须同时存在承载该元数据的 /// CqrsReflectionFallbackAttribute。如果基础合同缺失,生成器会静默跳过本轮发射;如果候选集合去重后没有任何可注册 /// handler,也会直接跳过 AddSource,避免输出空注册器。 /// /// /// 当 fallback handler 元数据非空但 runtime 缺少 CqrsReflectionFallbackAttribute 时, /// 该方法会报告 GF_Cqrs_001 并停止发射源码。这样可以避免生成一个表面可用、但会静默漏掉部分 handler 注册的半成品 /// registry。只有在静态注册结果与 fallback 契约同时成立时,才允许调用 AddSource。 /// /// private static void Execute( SourceProductionContext context, GenerationEnvironment generationEnvironment, ImmutableArray candidates) { if (!generationEnvironment.GenerationEnabled) return; var registrations = CollectRegistrations(candidates); if (registrations.Count == 0) return; var reflectionFallbackEmission = CreateReflectionFallbackEmissionSpec(generationEnvironment, registrations); if (!CanEmitGeneratedRegistry( generationEnvironment, reflectionFallbackEmission)) { ReportMissingReflectionFallbackContractDiagnostic( context, registrations); return; } context.AddSource( HintName, GenerateSource(generationEnvironment, registrations, reflectionFallbackEmission)); } /// /// 判断当前轮次是否允许输出生成注册器。 /// /// 当前轮次可用的 fallback 合同能力。 /// 当前轮次选定的 fallback 元数据发射策略。 /// /// 当没有 handler 依赖 fallback,或 runtime 已提供本轮策略所需的元数据承载重载时返回 ; /// 否则返回 ,调用方必须放弃生成以避免输出会静默漏注册的半成品注册器。 /// private static bool CanEmitGeneratedRegistry( GenerationEnvironment generationEnvironment, ReflectionFallbackEmissionSpec reflectionFallbackEmission) { if (!reflectionFallbackEmission.HasFallbackHandlers) return true; foreach (var attributeEmission in reflectionFallbackEmission.Attributes) { if (attributeEmission.EmitDirectTypeReferences) { if (!generationEnvironment.SupportsDirectReflectionFallbackTypes) return false; continue; } if (!generationEnvironment.SupportsNamedReflectionFallbackTypes) return false; } return true; } /// /// 报告当前轮次因缺少 fallback 元数据承载契约而无法安全生成注册器的诊断。 /// /// 源生产上下文。 /// 当前轮次汇总后的 handler 注册描述。 private static void ReportMissingReflectionFallbackContractDiagnostic( SourceProductionContext context, IReadOnlyList registrations) { var fallbackHandlerTypeMetadataNames = registrations .Select(static registration => registration.ReflectionFallbackHandlerTypeMetadataName) .Where(static typeMetadataName => !string.IsNullOrWhiteSpace(typeMetadataName)) .Distinct(StringComparer.Ordinal) .Cast() .ToArray(); var handlerList = string.Join( ", ", fallbackHandlerTypeMetadataNames.OrderBy(static name => name, StringComparer.Ordinal)); context.ReportDiagnostic(Diagnostic.Create( MissingReflectionFallbackContractDiagnostic, Location.None, handlerList, CqrsReflectionFallbackAttributeMetadataName)); } private static List CollectRegistrations( ImmutableArray candidates) { var registrations = new List(); // Partial declarations surface the same symbol through multiple syntax nodes. // Collapse them by implementation type so direct and reflected registrations stay stable and duplicate-free. var uniqueCandidates = new Dictionary(StringComparer.Ordinal); foreach (var candidate in candidates) { if (candidate is null) continue; uniqueCandidates[candidate.Value.ImplementationTypeDisplayName] = candidate.Value; } foreach (var candidate in uniqueCandidates.Values) { registrations.Add(new ImplementationRegistrationSpec( candidate.ImplementationTypeDisplayName, candidate.ImplementationLogName, candidate.Registrations, candidate.ReflectedImplementationRegistrations, candidate.PreciseReflectedRegistrations, candidate.ReflectionTypeMetadataName, candidate.ReflectionFallbackHandlerTypeDisplayName, candidate.ReflectionFallbackHandlerTypeMetadataName)); } registrations.Sort(static (left, right) => StringComparer.Ordinal.Compare(left.ImplementationLogName, right.ImplementationLogName)); return registrations; } /// /// 选择本轮生成应采用的 fallback 元数据发射策略。 /// /// /// 当所有 fallback handlers 都能被生成代码直接引用,且 runtime 暴露了 params Type[] 重载时, /// 优先输出单个直接 元数据特性;当 runtime 同时支持多个特性实例时, /// mixed 场景会拆分成“直接 + 字符串类型名”两类特性;其余场景统一回退到字符串元数据。 /// private static ReflectionFallbackEmissionSpec CreateReflectionFallbackEmissionSpec( GenerationEnvironment generationEnvironment, IReadOnlyList registrations) { var fallbackCandidates = CollectFallbackCandidates(registrations); if (fallbackCandidates.Count == 0) return new ReflectionFallbackEmissionSpec(ImmutableArray.Empty); var fallbackHandlerTypeMetadataNames = GetSortedFallbackMetadataNames(fallbackCandidates); var fallbackHandlerTypeDisplayNames = GetSortedDirectFallbackDisplayNames(fallbackCandidates); if (TryCreateDirectFallbackEmission( generationEnvironment, fallbackHandlerTypeDisplayNames, fallbackHandlerTypeMetadataNames, out var directFallbackEmission)) { return directFallbackEmission; } if (TryCreateMixedFallbackEmission( generationEnvironment, fallbackCandidates, fallbackHandlerTypeDisplayNames, out var mixedFallbackEmission)) { return mixedFallbackEmission; } return CreateNamedFallbackEmission(fallbackHandlerTypeMetadataNames); } /// /// 收集本轮所有 fallback handlers 的稳定元数据名和可选直接引用显示名。 /// private static Dictionary CollectFallbackCandidates( IReadOnlyList registrations) { var fallbackCandidates = new Dictionary(StringComparer.Ordinal); foreach (var registration in registrations) { if (string.IsNullOrWhiteSpace(registration.ReflectionFallbackHandlerTypeMetadataName)) continue; fallbackCandidates[registration.ReflectionFallbackHandlerTypeMetadataName!] = registration.ReflectionFallbackHandlerTypeDisplayName; } return fallbackCandidates; } /// /// 获取按稳定顺序排列的 fallback handler 元数据名称集合。 /// private static ImmutableArray GetSortedFallbackMetadataNames( IReadOnlyDictionary fallbackCandidates) { return fallbackCandidates.Keys .OrderBy(static metadataName => metadataName, StringComparer.Ordinal) .ToImmutableArray(); } /// /// 获取按稳定顺序排列的可直接引用 fallback handler 显示名集合。 /// private static ImmutableArray GetSortedDirectFallbackDisplayNames( IReadOnlyDictionary fallbackCandidates) { return fallbackCandidates.Values .Where(static typeDisplayName => !string.IsNullOrWhiteSpace(typeDisplayName)) .Cast() .OrderBy(static typeDisplayName => typeDisplayName, StringComparer.Ordinal) .ToImmutableArray(); } /// /// 当全部 fallback handlers 都可直接引用时,尝试创建直接 元数据发射策略。 /// private static bool TryCreateDirectFallbackEmission( GenerationEnvironment generationEnvironment, ImmutableArray fallbackHandlerTypeDisplayNames, ImmutableArray fallbackHandlerTypeMetadataNames, out ReflectionFallbackEmissionSpec emission) { if (generationEnvironment.SupportsDirectReflectionFallbackTypes && fallbackHandlerTypeDisplayNames.Length == fallbackHandlerTypeMetadataNames.Length) { emission = new ReflectionFallbackEmissionSpec( [ new ReflectionFallbackAttributeEmissionSpec( EmitDirectTypeReferences: true, fallbackHandlerTypeDisplayNames) ]); return true; } emission = default; return false; } /// /// 当 runtime 允许多个 fallback 特性实例时,尝试为 mixed 场景拆分直接 与字符串元数据。 /// private static bool TryCreateMixedFallbackEmission( GenerationEnvironment generationEnvironment, IReadOnlyDictionary fallbackCandidates, ImmutableArray fallbackHandlerTypeDisplayNames, out ReflectionFallbackEmissionSpec emission) { if (!generationEnvironment.SupportsDirectReflectionFallbackTypes || !generationEnvironment.SupportsNamedReflectionFallbackTypes || !generationEnvironment.SupportsMultipleReflectionFallbackAttributes || fallbackHandlerTypeDisplayNames.Length == 0) { emission = default; return false; } var namedOnlyFallbackMetadataNames = fallbackCandidates .Where(static pair => string.IsNullOrWhiteSpace(pair.Value)) .Select(static pair => pair.Key) .OrderBy(static metadataName => metadataName, StringComparer.Ordinal) .ToImmutableArray(); if (namedOnlyFallbackMetadataNames.Length == 0) { emission = default; return false; } emission = new ReflectionFallbackEmissionSpec( [ new ReflectionFallbackAttributeEmissionSpec( EmitDirectTypeReferences: true, fallbackHandlerTypeDisplayNames), new ReflectionFallbackAttributeEmissionSpec( EmitDirectTypeReferences: false, namedOnlyFallbackMetadataNames) ]); return true; } /// /// 创建统一的字符串 fallback 元数据发射策略。 /// private static ReflectionFallbackEmissionSpec CreateNamedFallbackEmission( ImmutableArray fallbackHandlerTypeMetadataNames) { return new ReflectionFallbackEmissionSpec( [ new ReflectionFallbackAttributeEmissionSpec( EmitDirectTypeReferences: false, fallbackHandlerTypeMetadataNames) ]); } /// /// 判断目标特性是否暴露了指定元素类型的 params T[] 构造函数。 /// private static bool HasParamsArrayConstructor(INamedTypeSymbol attributeType, ITypeSymbol elementType) { foreach (var constructor in attributeType.InstanceConstructors) { if (constructor.Parameters.Length != 1) continue; var parameter = constructor.Parameters[0]; if (!parameter.IsParams) continue; if (parameter.Type is IArrayTypeSymbol { Rank: 1 } arrayType && SymbolEqualityComparer.Default.Equals(arrayType.ElementType, elementType)) { return true; } } return false; } /// /// 判断目标特性的 是否允许在同一程序集上声明多个实例。 /// private static bool SupportsMultipleAttributeInstances(INamedTypeSymbol attributeType) { foreach (var attribute in attributeType.GetAttributes()) { if (!string.Equals( attribute.AttributeClass?.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat), "global::System.AttributeUsageAttribute", StringComparison.Ordinal)) { continue; } foreach (var namedArgument in attribute.NamedArguments) { if (string.Equals(namedArgument.Key, "AllowMultiple", StringComparison.Ordinal) && namedArgument.Value.Value is bool allowMultiple) { return allowMultiple; } } return false; } return false; } private static bool IsConcreteHandlerType(INamedTypeSymbol type) { return type.TypeKind is TypeKind.Class or TypeKind.Struct && !type.IsAbstract && !ContainsGenericParameters(type); } private static bool ContainsGenericParameters(INamedTypeSymbol type) { for (var current = type; current is not null; current = current.ContainingType) { if (current.TypeParameters.Length > 0) return true; } return false; } private static bool IsSupportedHandlerInterface(INamedTypeSymbol interfaceType) { if (!interfaceType.IsGenericType) return false; var definitionMetadataName = GetFullyQualifiedMetadataName(interfaceType.OriginalDefinition); return string.Equals(definitionMetadataName, IRequestHandlerMetadataName, StringComparison.Ordinal) || string.Equals(definitionMetadataName, INotificationHandlerMetadataName, StringComparison.Ordinal) || string.Equals(definitionMetadataName, IStreamRequestHandlerMetadataName, StringComparison.Ordinal); } private static string GetFullyQualifiedMetadataName(INamedTypeSymbol type) { var nestedTypes = new Stack(); for (var current = type; current is not null; current = current.ContainingType) { nestedTypes.Push(current.MetadataName); } var builder = new StringBuilder(); if (!type.ContainingNamespace.IsGlobalNamespace) { builder.Append(type.ContainingNamespace.ToDisplayString()); builder.Append('.'); } while (nestedTypes.Count > 0) { builder.Append(nestedTypes.Pop()); if (nestedTypes.Count > 0) builder.Append('.'); } return builder.ToString(); } private static string GetReflectionTypeMetadataName(INamedTypeSymbol type) { var nestedTypes = new Stack(); for (var current = type; current is not null; current = current.ContainingType) { nestedTypes.Push(current.MetadataName); } var builder = new StringBuilder(); if (!type.ContainingNamespace.IsGlobalNamespace) { builder.Append(type.ContainingNamespace.ToDisplayString()); builder.Append('.'); } var isFirstType = true; while (nestedTypes.Count > 0) { if (!isFirstType) builder.Append('+'); builder.Append(nestedTypes.Pop()); isFirstType = false; } return builder.ToString(); } private static string GetTypeSortKey(ITypeSymbol type) { return type.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat); } private static string GetLogDisplayName(ITypeSymbol type) { return GetTypeSortKey(type).Replace("global::", string.Empty); } }