mirror of
https://github.com/GeWuYou/GFramework.git
synced 2026-05-07 00:39:00 +08:00
- 优化 CqrsHandlerRegistryGenerator 的 fallback 合同探测与元数据发射策略,在可直接引用 handlers 时优先输出 Type 元数据 - 补充 SourceGenerators 回归测试,覆盖字符串合同兼容路径与直接 Type 元数据优先级 - 更新 CQRS 生成器说明与 ai-plan 恢复文档,记录 RP-051 的验证结果与后续方向
319 lines
13 KiB
C#
319 lines
13 KiB
C#
namespace GFramework.Cqrs.SourceGenerators.Cqrs;
|
|
|
|
/// <summary>
|
|
/// 为当前编译程序集生成 CQRS 处理器注册器,以减少运行时的程序集反射扫描成本。
|
|
/// </summary>
|
|
public sealed partial class CqrsHandlerRegistryGenerator
|
|
{
|
|
private readonly record struct HandlerRegistrationSpec(
|
|
string HandlerInterfaceDisplayName,
|
|
string ImplementationTypeDisplayName,
|
|
string HandlerInterfaceLogName,
|
|
string ImplementationLogName);
|
|
|
|
private readonly record struct ReflectedImplementationRegistrationSpec(
|
|
string HandlerInterfaceDisplayName,
|
|
string HandlerInterfaceLogName);
|
|
|
|
private readonly record struct OrderedRegistrationSpec(
|
|
string HandlerInterfaceLogName,
|
|
OrderedRegistrationKind Kind,
|
|
int Index);
|
|
|
|
private readonly record struct GeneratedRegistrySourceShape(
|
|
bool HasReflectedImplementationRegistrations,
|
|
bool HasPreciseReflectedRegistrations,
|
|
bool HasReflectionTypeLookups,
|
|
bool HasExternalAssemblyTypeLookups)
|
|
{
|
|
public bool RequiresRegistryAssemblyVariable =>
|
|
HasReflectedImplementationRegistrations ||
|
|
HasPreciseReflectedRegistrations ||
|
|
HasReflectionTypeLookups;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 标记某条 handler 注册语句在生成阶段采用的表达策略。
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// 该枚举只服务于输出排序与代码分支选择,用来保证生成注册器在“直接注册”
|
|
/// “反射实现类型查找”和“精确运行时类型解析”之间保持稳定顺序。
|
|
/// </remarks>
|
|
private enum OrderedRegistrationKind
|
|
{
|
|
Direct,
|
|
ReflectedImplementation,
|
|
PreciseReflected
|
|
}
|
|
|
|
/// <summary>
|
|
/// 描述生成注册器中某个运行时类型引用的构造方式。
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// 某些 handler 服务类型可以直接以 <c>typeof(...)</c> 输出,某些则需要在运行时补充
|
|
/// 反射查找、数组封装或泛型实参重建。该记录把这些差异收敛为统一的递归结构,
|
|
/// 供源码输出阶段生成稳定的类型解析语句。
|
|
/// </remarks>
|
|
private sealed record RuntimeTypeReferenceSpec(
|
|
string? TypeDisplayName,
|
|
string? ReflectionTypeMetadataName,
|
|
string? ReflectionAssemblyName,
|
|
RuntimeTypeReferenceSpec? ArrayElementTypeReference,
|
|
int ArrayRank,
|
|
RuntimeTypeReferenceSpec? PointerElementTypeReference,
|
|
RuntimeTypeReferenceSpec? GenericTypeDefinitionReference,
|
|
ImmutableArray<RuntimeTypeReferenceSpec> GenericTypeArguments)
|
|
{
|
|
/// <summary>
|
|
/// 创建一个可直接通过 <c>typeof(...)</c> 表达的类型引用。
|
|
/// </summary>
|
|
public static RuntimeTypeReferenceSpec FromDirectReference(string typeDisplayName)
|
|
{
|
|
return new RuntimeTypeReferenceSpec(
|
|
typeDisplayName,
|
|
null,
|
|
null,
|
|
null,
|
|
0,
|
|
null,
|
|
null,
|
|
ImmutableArray<RuntimeTypeReferenceSpec>.Empty);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 创建一个需要从当前消费端程序集反射解析的类型引用。
|
|
/// </summary>
|
|
public static RuntimeTypeReferenceSpec FromReflectionLookup(string reflectionTypeMetadataName)
|
|
{
|
|
return new RuntimeTypeReferenceSpec(
|
|
null,
|
|
reflectionTypeMetadataName,
|
|
null,
|
|
null,
|
|
0,
|
|
null,
|
|
null,
|
|
ImmutableArray<RuntimeTypeReferenceSpec>.Empty);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 创建一个需要从被引用程序集反射解析的类型引用。
|
|
/// </summary>
|
|
public static RuntimeTypeReferenceSpec FromExternalReflectionLookup(
|
|
string reflectionAssemblyName,
|
|
string reflectionTypeMetadataName)
|
|
{
|
|
return new RuntimeTypeReferenceSpec(
|
|
null,
|
|
reflectionTypeMetadataName,
|
|
reflectionAssemblyName,
|
|
null,
|
|
0,
|
|
null,
|
|
null,
|
|
ImmutableArray<RuntimeTypeReferenceSpec>.Empty);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 创建一个数组类型引用。
|
|
/// </summary>
|
|
public static RuntimeTypeReferenceSpec FromArray(RuntimeTypeReferenceSpec elementTypeReference, int arrayRank)
|
|
{
|
|
return new RuntimeTypeReferenceSpec(
|
|
null,
|
|
null,
|
|
null,
|
|
elementTypeReference,
|
|
arrayRank,
|
|
null,
|
|
null,
|
|
ImmutableArray<RuntimeTypeReferenceSpec>.Empty);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 创建一个封闭泛型类型引用。
|
|
/// </summary>
|
|
public static RuntimeTypeReferenceSpec FromConstructedGeneric(
|
|
RuntimeTypeReferenceSpec genericTypeDefinitionReference,
|
|
ImmutableArray<RuntimeTypeReferenceSpec> genericTypeArguments)
|
|
{
|
|
return new RuntimeTypeReferenceSpec(
|
|
null,
|
|
null,
|
|
null,
|
|
null,
|
|
0,
|
|
null,
|
|
genericTypeDefinitionReference,
|
|
genericTypeArguments);
|
|
}
|
|
}
|
|
|
|
private readonly record struct PreciseReflectedRegistrationSpec(
|
|
string OpenHandlerTypeDisplayName,
|
|
string HandlerInterfaceLogName,
|
|
ImmutableArray<RuntimeTypeReferenceSpec> ServiceTypeArguments);
|
|
|
|
/// <summary>
|
|
/// 描述本轮生成应如何发射程序集级 reflection fallback 元数据。
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// 生成器会优先尝试使用 <c>typeof(...)</c> 形式的 <see cref="Type" /> 元数据,
|
|
/// 以减少运行时再做字符串类型名回查的成本;但当任一 fallback handler 仍无法被生成代码直接引用时,
|
|
/// 会整体回退到字符串元数据,避免 mixed 场景下遗漏剩余 handler。
|
|
/// </remarks>
|
|
private readonly record struct ReflectionFallbackEmissionSpec(
|
|
bool EmitDirectTypeReferences,
|
|
ImmutableArray<string> HandlerTypeDisplayNames,
|
|
ImmutableArray<string> HandlerTypeMetadataNames)
|
|
{
|
|
/// <summary>
|
|
/// 获取当前是否需要发射任何 fallback 元数据。
|
|
/// </summary>
|
|
public bool HasFallbackHandlers =>
|
|
!HandlerTypeDisplayNames.IsDefaultOrEmpty || !HandlerTypeMetadataNames.IsDefaultOrEmpty;
|
|
}
|
|
|
|
private readonly record struct ImplementationRegistrationSpec(
|
|
string ImplementationTypeDisplayName,
|
|
string ImplementationLogName,
|
|
ImmutableArray<HandlerRegistrationSpec> DirectRegistrations,
|
|
ImmutableArray<ReflectedImplementationRegistrationSpec> ReflectedImplementationRegistrations,
|
|
ImmutableArray<PreciseReflectedRegistrationSpec> PreciseReflectedRegistrations,
|
|
string? ReflectionTypeMetadataName,
|
|
string? ReflectionFallbackHandlerTypeDisplayName,
|
|
string? ReflectionFallbackHandlerTypeMetadataName);
|
|
|
|
private readonly struct HandlerCandidateAnalysis : IEquatable<HandlerCandidateAnalysis>
|
|
{
|
|
public HandlerCandidateAnalysis(
|
|
string implementationTypeDisplayName,
|
|
string implementationLogName,
|
|
ImmutableArray<HandlerRegistrationSpec> registrations,
|
|
ImmutableArray<ReflectedImplementationRegistrationSpec> reflectedImplementationRegistrations,
|
|
ImmutableArray<PreciseReflectedRegistrationSpec> preciseReflectedRegistrations,
|
|
string? reflectionTypeMetadataName,
|
|
string? reflectionFallbackHandlerTypeDisplayName,
|
|
string? reflectionFallbackHandlerTypeMetadataName)
|
|
{
|
|
ImplementationTypeDisplayName = implementationTypeDisplayName;
|
|
ImplementationLogName = implementationLogName;
|
|
Registrations = registrations;
|
|
ReflectedImplementationRegistrations = reflectedImplementationRegistrations;
|
|
PreciseReflectedRegistrations = preciseReflectedRegistrations;
|
|
ReflectionTypeMetadataName = reflectionTypeMetadataName;
|
|
ReflectionFallbackHandlerTypeDisplayName = reflectionFallbackHandlerTypeDisplayName;
|
|
ReflectionFallbackHandlerTypeMetadataName = reflectionFallbackHandlerTypeMetadataName;
|
|
}
|
|
|
|
public string ImplementationTypeDisplayName { get; }
|
|
|
|
public string ImplementationLogName { get; }
|
|
|
|
public ImmutableArray<HandlerRegistrationSpec> Registrations { get; }
|
|
|
|
public ImmutableArray<ReflectedImplementationRegistrationSpec> ReflectedImplementationRegistrations { get; }
|
|
|
|
public ImmutableArray<PreciseReflectedRegistrationSpec> PreciseReflectedRegistrations { get; }
|
|
|
|
public string? ReflectionTypeMetadataName { get; }
|
|
|
|
public string? ReflectionFallbackHandlerTypeDisplayName { get; }
|
|
|
|
public string? ReflectionFallbackHandlerTypeMetadataName { get; }
|
|
|
|
public bool Equals(HandlerCandidateAnalysis other)
|
|
{
|
|
if (!string.Equals(ImplementationTypeDisplayName, other.ImplementationTypeDisplayName,
|
|
StringComparison.Ordinal) ||
|
|
!string.Equals(ImplementationLogName, other.ImplementationLogName, StringComparison.Ordinal) ||
|
|
!string.Equals(ReflectionTypeMetadataName, other.ReflectionTypeMetadataName,
|
|
StringComparison.Ordinal) ||
|
|
!string.Equals(
|
|
ReflectionFallbackHandlerTypeDisplayName,
|
|
other.ReflectionFallbackHandlerTypeDisplayName,
|
|
StringComparison.Ordinal) ||
|
|
!string.Equals(
|
|
ReflectionFallbackHandlerTypeMetadataName,
|
|
other.ReflectionFallbackHandlerTypeMetadataName,
|
|
StringComparison.Ordinal) ||
|
|
Registrations.Length != other.Registrations.Length ||
|
|
ReflectedImplementationRegistrations.Length != other.ReflectedImplementationRegistrations.Length ||
|
|
PreciseReflectedRegistrations.Length != other.PreciseReflectedRegistrations.Length)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
for (var index = 0; index < Registrations.Length; index++)
|
|
{
|
|
if (!Registrations[index].Equals(other.Registrations[index]))
|
|
return false;
|
|
}
|
|
|
|
for (var index = 0; index < ReflectedImplementationRegistrations.Length; index++)
|
|
{
|
|
if (!ReflectedImplementationRegistrations[index].Equals(
|
|
other.ReflectedImplementationRegistrations[index]))
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
for (var index = 0; index < PreciseReflectedRegistrations.Length; index++)
|
|
{
|
|
if (!PreciseReflectedRegistrations[index].Equals(other.PreciseReflectedRegistrations[index]))
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
public override bool Equals(object? obj)
|
|
{
|
|
return obj is HandlerCandidateAnalysis other && Equals(other);
|
|
}
|
|
|
|
public override int GetHashCode()
|
|
{
|
|
unchecked
|
|
{
|
|
var hashCode = StringComparer.Ordinal.GetHashCode(ImplementationTypeDisplayName);
|
|
hashCode = (hashCode * 397) ^ StringComparer.Ordinal.GetHashCode(ImplementationLogName);
|
|
hashCode = (hashCode * 397) ^
|
|
(ReflectionTypeMetadataName is null
|
|
? 0
|
|
: StringComparer.Ordinal.GetHashCode(ReflectionTypeMetadataName));
|
|
hashCode = (hashCode * 397) ^
|
|
(ReflectionFallbackHandlerTypeDisplayName is null
|
|
? 0
|
|
: StringComparer.Ordinal.GetHashCode(ReflectionFallbackHandlerTypeDisplayName));
|
|
hashCode = (hashCode * 397) ^
|
|
(ReflectionFallbackHandlerTypeMetadataName is null
|
|
? 0
|
|
: StringComparer.Ordinal.GetHashCode(ReflectionFallbackHandlerTypeMetadataName));
|
|
foreach (var registration in Registrations)
|
|
{
|
|
hashCode = (hashCode * 397) ^ registration.GetHashCode();
|
|
}
|
|
|
|
foreach (var reflectedImplementationRegistration in ReflectedImplementationRegistrations)
|
|
{
|
|
hashCode = (hashCode * 397) ^ reflectedImplementationRegistration.GetHashCode();
|
|
}
|
|
|
|
foreach (var preciseReflectedRegistration in PreciseReflectedRegistrations)
|
|
{
|
|
hashCode = (hashCode * 397) ^ preciseReflectedRegistration.GetHashCode();
|
|
}
|
|
|
|
return hashCode;
|
|
}
|
|
}
|
|
}
|
|
|
|
private readonly record struct GenerationEnvironment(
|
|
bool GenerationEnabled,
|
|
bool SupportsNamedReflectionFallbackTypes,
|
|
bool SupportsDirectReflectionFallbackTypes);
|
|
}
|