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);
}
}