mirror of
https://github.com/GeWuYou/GFramework.git
synced 2026-05-07 00:39:00 +08:00
feat(cqrs): 添加 CQRS 处理器注册生成器
- 实现 CqrsHandlerRegistryGenerator 源代码生成器 - 为 CQRS 请求处理器、通知处理器和流请求处理器生成注册代码 - 减少运行时程序集反射扫描开销 - 支持直接类型引用和反射加载两种注册方式 - 提供完整的单元测试验证生成器功能 - 实现对私有嵌套类型的反射注册支持
This commit is contained in:
parent
ba6a358df1
commit
76bb9671d5
@ -142,6 +142,39 @@ public class CqrsHandlerRegistryGeneratorTests
|
|||||||
|
|
||||||
""";
|
""";
|
||||||
|
|
||||||
|
private const string HiddenImplementationDirectInterfaceRegistrationExpected = """
|
||||||
|
// <auto-generated />
|
||||||
|
#nullable enable
|
||||||
|
|
||||||
|
[assembly: global::GFramework.Cqrs.CqrsHandlerRegistryAttribute(typeof(global::GFramework.Generated.Cqrs.__GFrameworkGeneratedCqrsHandlerRegistry))]
|
||||||
|
|
||||||
|
namespace GFramework.Generated.Cqrs;
|
||||||
|
|
||||||
|
internal sealed class __GFrameworkGeneratedCqrsHandlerRegistry : global::GFramework.Cqrs.ICqrsHandlerRegistry
|
||||||
|
{
|
||||||
|
public void Register(global::Microsoft.Extensions.DependencyInjection.IServiceCollection services, global::GFramework.Core.Abstractions.Logging.ILogger logger)
|
||||||
|
{
|
||||||
|
if (services is null)
|
||||||
|
throw new global::System.ArgumentNullException(nameof(services));
|
||||||
|
if (logger is null)
|
||||||
|
throw new global::System.ArgumentNullException(nameof(logger));
|
||||||
|
|
||||||
|
var registryAssembly = typeof(global::GFramework.Generated.Cqrs.__GFrameworkGeneratedCqrsHandlerRegistry).Assembly;
|
||||||
|
|
||||||
|
var implementationType0 = registryAssembly.GetType("TestApp.Container+HiddenHandler", throwOnError: false, ignoreCase: false);
|
||||||
|
if (implementationType0 is not null)
|
||||||
|
{
|
||||||
|
global::Microsoft.Extensions.DependencyInjection.ServiceCollectionServiceExtensions.AddTransient(
|
||||||
|
services,
|
||||||
|
typeof(global::GFramework.Cqrs.Abstractions.Cqrs.IRequestHandler<global::TestApp.VisibleRequest, string>),
|
||||||
|
implementationType0);
|
||||||
|
logger.Debug("Registered CQRS handler TestApp.Container.HiddenHandler as GFramework.Cqrs.Abstractions.Cqrs.IRequestHandler<TestApp.VisibleRequest, string>.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
""";
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 验证生成器会为当前程序集中的 request、notification 和 stream 处理器生成稳定顺序的注册器。
|
/// 验证生成器会为当前程序集中的 request、notification 和 stream 处理器生成稳定顺序的注册器。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -339,6 +372,78 @@ public class CqrsHandlerRegistryGeneratorTests
|
|||||||
("CqrsHandlerRegistry.g.cs", HiddenNestedHandlerSelfRegistrationExpected));
|
("CqrsHandlerRegistry.g.cs", HiddenNestedHandlerSelfRegistrationExpected));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 验证当隐藏实现类型的 handler 接口仍可被生成代码直接引用时,
|
||||||
|
/// 生成器只会定向反射实现类型,而不会再生成基于 <c>GetInterfaces()</c> 的接口发现辅助逻辑。
|
||||||
|
/// </summary>
|
||||||
|
[Test]
|
||||||
|
public async Task
|
||||||
|
Generates_Direct_Interface_Registrations_For_Hidden_Implementation_When_Handler_Interface_Is_Public()
|
||||||
|
{
|
||||||
|
const string source = """
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Microsoft.Extensions.DependencyInjection
|
||||||
|
{
|
||||||
|
public interface IServiceCollection { }
|
||||||
|
|
||||||
|
public static class ServiceCollectionServiceExtensions
|
||||||
|
{
|
||||||
|
public static void AddTransient(IServiceCollection services, Type serviceType, Type implementationType) { }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace GFramework.Core.Abstractions.Logging
|
||||||
|
{
|
||||||
|
public interface ILogger
|
||||||
|
{
|
||||||
|
void Debug(string msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace GFramework.Cqrs.Abstractions.Cqrs
|
||||||
|
{
|
||||||
|
public interface IRequest<TResponse> { }
|
||||||
|
public interface INotification { }
|
||||||
|
public interface IStreamRequest<TResponse> { }
|
||||||
|
|
||||||
|
public interface IRequestHandler<in TRequest, TResponse> where TRequest : IRequest<TResponse> { }
|
||||||
|
public interface INotificationHandler<in TNotification> where TNotification : INotification { }
|
||||||
|
public interface IStreamRequestHandler<in TRequest, out TResponse> where TRequest : IStreamRequest<TResponse> { }
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace GFramework.Cqrs
|
||||||
|
{
|
||||||
|
public interface ICqrsHandlerRegistry
|
||||||
|
{
|
||||||
|
void Register(Microsoft.Extensions.DependencyInjection.IServiceCollection services, GFramework.Core.Abstractions.Logging.ILogger logger);
|
||||||
|
}
|
||||||
|
|
||||||
|
[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
|
||||||
|
public sealed class CqrsHandlerRegistryAttribute : Attribute
|
||||||
|
{
|
||||||
|
public CqrsHandlerRegistryAttribute(Type registryType) { }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace TestApp
|
||||||
|
{
|
||||||
|
using GFramework.Cqrs.Abstractions.Cqrs;
|
||||||
|
|
||||||
|
public sealed record VisibleRequest() : IRequest<string>;
|
||||||
|
|
||||||
|
public sealed class Container
|
||||||
|
{
|
||||||
|
private sealed class HiddenHandler : IRequestHandler<VisibleRequest, string> { }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
""";
|
||||||
|
|
||||||
|
await GeneratorTest<CqrsHandlerRegistryGenerator>.RunAsync(
|
||||||
|
source,
|
||||||
|
("CqrsHandlerRegistry.g.cs", HiddenImplementationDirectInterfaceRegistrationExpected));
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 验证即使 runtime 仍暴露旧版无参 fallback marker,生成器也会优先在生成注册器内部处理隐藏 handler,
|
/// 验证即使 runtime 仍暴露旧版无参 fallback marker,生成器也会优先在生成注册器内部处理隐藏 handler,
|
||||||
/// 不再输出 fallback marker。
|
/// 不再输出 fallback marker。
|
||||||
|
|||||||
@ -86,22 +86,35 @@ public sealed class CqrsHandlerRegistryGenerator : IIncrementalGenerator
|
|||||||
|
|
||||||
var implementationTypeDisplayName = type.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat);
|
var implementationTypeDisplayName = type.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat);
|
||||||
var implementationLogName = GetLogDisplayName(type);
|
var implementationLogName = GetLogDisplayName(type);
|
||||||
if (!CanReferenceFromGeneratedRegistry(type) ||
|
var canReferenceImplementation = CanReferenceFromGeneratedRegistry(type);
|
||||||
handlerInterfaces.Any(interfaceType => !CanReferenceFromGeneratedRegistry(interfaceType)))
|
|
||||||
{
|
|
||||||
// Non-public handlers and handlers closed over non-public message types cannot appear in typeof(...)
|
|
||||||
// expressions inside generated code. Preserve generator hit rate by resolving just that implementation
|
|
||||||
// type back from the current assembly instead of asking the runtime registrar to rescan the assembly.
|
|
||||||
return new HandlerCandidateAnalysis(
|
|
||||||
implementationTypeDisplayName,
|
|
||||||
implementationLogName,
|
|
||||||
ImmutableArray<HandlerRegistrationSpec>.Empty,
|
|
||||||
GetReflectionTypeMetadataName(type));
|
|
||||||
}
|
|
||||||
|
|
||||||
var registrations = ImmutableArray.CreateBuilder<HandlerRegistrationSpec>(handlerInterfaces.Length);
|
var registrations = ImmutableArray.CreateBuilder<HandlerRegistrationSpec>(handlerInterfaces.Length);
|
||||||
|
var reflectedImplementationRegistrations =
|
||||||
|
ImmutableArray.CreateBuilder<ReflectedImplementationRegistrationSpec>(handlerInterfaces.Length);
|
||||||
foreach (var handlerInterface in handlerInterfaces)
|
foreach (var handlerInterface in handlerInterfaces)
|
||||||
{
|
{
|
||||||
|
var canReferenceHandlerInterface = CanReferenceFromGeneratedRegistry(handlerInterface);
|
||||||
|
if (!canReferenceImplementation || !canReferenceHandlerInterface)
|
||||||
|
{
|
||||||
|
if (!canReferenceImplementation && canReferenceHandlerInterface)
|
||||||
|
{
|
||||||
|
reflectedImplementationRegistrations.Add(new ReflectedImplementationRegistrationSpec(
|
||||||
|
handlerInterface.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat),
|
||||||
|
GetLogDisplayName(handlerInterface)));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Non-public handlers closed over non-public message types still cannot be expressed purely as
|
||||||
|
// typeof(...) registrations. Preserve generator hit rate by resolving only the affected
|
||||||
|
// implementation back from the current assembly instead of asking the runtime registrar to rescan
|
||||||
|
// the whole assembly.
|
||||||
|
return new HandlerCandidateAnalysis(
|
||||||
|
implementationTypeDisplayName,
|
||||||
|
implementationLogName,
|
||||||
|
ImmutableArray<HandlerRegistrationSpec>.Empty,
|
||||||
|
ImmutableArray<ReflectedImplementationRegistrationSpec>.Empty,
|
||||||
|
GetReflectionTypeMetadataName(type));
|
||||||
|
}
|
||||||
|
|
||||||
registrations.Add(new HandlerRegistrationSpec(
|
registrations.Add(new HandlerRegistrationSpec(
|
||||||
handlerInterface.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat),
|
handlerInterface.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat),
|
||||||
implementationTypeDisplayName,
|
implementationTypeDisplayName,
|
||||||
@ -112,8 +125,9 @@ public sealed class CqrsHandlerRegistryGenerator : IIncrementalGenerator
|
|||||||
return new HandlerCandidateAnalysis(
|
return new HandlerCandidateAnalysis(
|
||||||
implementationTypeDisplayName,
|
implementationTypeDisplayName,
|
||||||
implementationLogName,
|
implementationLogName,
|
||||||
registrations.MoveToImmutable(),
|
registrations.ToImmutable(),
|
||||||
null);
|
reflectedImplementationRegistrations.ToImmutable(),
|
||||||
|
canReferenceImplementation ? null : GetReflectionTypeMetadataName(type));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void Execute(SourceProductionContext context, GenerationEnvironment generationEnvironment,
|
private static void Execute(SourceProductionContext context, GenerationEnvironment generationEnvironment,
|
||||||
@ -155,6 +169,7 @@ public sealed class CqrsHandlerRegistryGenerator : IIncrementalGenerator
|
|||||||
candidate.ImplementationTypeDisplayName,
|
candidate.ImplementationTypeDisplayName,
|
||||||
candidate.ImplementationLogName,
|
candidate.ImplementationLogName,
|
||||||
candidate.Registrations,
|
candidate.Registrations,
|
||||||
|
candidate.ReflectedImplementationRegistrations,
|
||||||
candidate.ReflectionTypeMetadataName));
|
candidate.ReflectionTypeMetadataName));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -302,8 +317,11 @@ public sealed class CqrsHandlerRegistryGenerator : IIncrementalGenerator
|
|||||||
private static string GenerateSource(
|
private static string GenerateSource(
|
||||||
IReadOnlyList<ImplementationRegistrationSpec> registrations)
|
IReadOnlyList<ImplementationRegistrationSpec> registrations)
|
||||||
{
|
{
|
||||||
var hasReflectionRegistrations = registrations.Any(static registration =>
|
var hasReflectedImplementationRegistrations = registrations.Any(static registration =>
|
||||||
!string.IsNullOrWhiteSpace(registration.ReflectionTypeMetadataName));
|
!registration.ReflectedImplementationRegistrations.IsDefaultOrEmpty);
|
||||||
|
var hasFullReflectionRegistrations = registrations.Any(static registration =>
|
||||||
|
!string.IsNullOrWhiteSpace(registration.ReflectionTypeMetadataName) &&
|
||||||
|
registration.ReflectedImplementationRegistrations.IsDefaultOrEmpty);
|
||||||
var builder = new StringBuilder();
|
var builder = new StringBuilder();
|
||||||
builder.AppendLine("// <auto-generated />");
|
builder.AppendLine("// <auto-generated />");
|
||||||
builder.AppendLine("#nullable enable");
|
builder.AppendLine("#nullable enable");
|
||||||
@ -336,7 +354,7 @@ public sealed class CqrsHandlerRegistryGenerator : IIncrementalGenerator
|
|||||||
builder.AppendLine(" throw new global::System.ArgumentNullException(nameof(services));");
|
builder.AppendLine(" throw new global::System.ArgumentNullException(nameof(services));");
|
||||||
builder.AppendLine(" if (logger is null)");
|
builder.AppendLine(" if (logger is null)");
|
||||||
builder.AppendLine(" throw new global::System.ArgumentNullException(nameof(logger));");
|
builder.AppendLine(" throw new global::System.ArgumentNullException(nameof(logger));");
|
||||||
if (hasReflectionRegistrations)
|
if (hasReflectedImplementationRegistrations || hasFullReflectionRegistrations)
|
||||||
{
|
{
|
||||||
builder.AppendLine();
|
builder.AppendLine();
|
||||||
builder.Append(" var registryAssembly = typeof(global::");
|
builder.Append(" var registryAssembly = typeof(global::");
|
||||||
@ -349,8 +367,15 @@ public sealed class CqrsHandlerRegistryGenerator : IIncrementalGenerator
|
|||||||
if (registrations.Count > 0)
|
if (registrations.Count > 0)
|
||||||
builder.AppendLine();
|
builder.AppendLine();
|
||||||
|
|
||||||
foreach (var registration in registrations)
|
for (var registrationIndex = 0; registrationIndex < registrations.Count; registrationIndex++)
|
||||||
{
|
{
|
||||||
|
var registration = registrations[registrationIndex];
|
||||||
|
if (!registration.ReflectedImplementationRegistrations.IsDefaultOrEmpty)
|
||||||
|
{
|
||||||
|
AppendReflectedImplementationRegistrations(builder, registration, registrationIndex);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (!string.IsNullOrWhiteSpace(registration.ReflectionTypeMetadataName))
|
if (!string.IsNullOrWhiteSpace(registration.ReflectionTypeMetadataName))
|
||||||
{
|
{
|
||||||
AppendReflectionRegistration(builder, registration.ReflectionTypeMetadataName!);
|
AppendReflectionRegistration(builder, registration.ReflectionTypeMetadataName!);
|
||||||
@ -378,7 +403,7 @@ public sealed class CqrsHandlerRegistryGenerator : IIncrementalGenerator
|
|||||||
|
|
||||||
builder.AppendLine(" }");
|
builder.AppendLine(" }");
|
||||||
|
|
||||||
if (hasReflectionRegistrations)
|
if (hasFullReflectionRegistrations)
|
||||||
{
|
{
|
||||||
builder.AppendLine();
|
builder.AppendLine();
|
||||||
AppendReflectionHelpers(builder);
|
AppendReflectionHelpers(builder);
|
||||||
@ -395,6 +420,43 @@ public sealed class CqrsHandlerRegistryGenerator : IIncrementalGenerator
|
|||||||
builder.AppendLine("\");");
|
builder.AppendLine("\");");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void AppendReflectedImplementationRegistrations(
|
||||||
|
StringBuilder builder,
|
||||||
|
ImplementationRegistrationSpec registration,
|
||||||
|
int registrationIndex)
|
||||||
|
{
|
||||||
|
var implementationVariableName = $"implementationType{registrationIndex}";
|
||||||
|
builder.Append(" var ");
|
||||||
|
builder.Append(implementationVariableName);
|
||||||
|
builder.Append(" = registryAssembly.GetType(\"");
|
||||||
|
builder.Append(EscapeStringLiteral(registration.ReflectionTypeMetadataName!));
|
||||||
|
builder.AppendLine("\", throwOnError: false, ignoreCase: false);");
|
||||||
|
builder.Append(" if (");
|
||||||
|
builder.Append(implementationVariableName);
|
||||||
|
builder.AppendLine(" is not null)");
|
||||||
|
builder.AppendLine(" {");
|
||||||
|
|
||||||
|
foreach (var reflectedRegistration in registration.ReflectedImplementationRegistrations)
|
||||||
|
{
|
||||||
|
builder.AppendLine(
|
||||||
|
" global::Microsoft.Extensions.DependencyInjection.ServiceCollectionServiceExtensions.AddTransient(");
|
||||||
|
builder.AppendLine(" services,");
|
||||||
|
builder.Append(" typeof(");
|
||||||
|
builder.Append(reflectedRegistration.HandlerInterfaceDisplayName);
|
||||||
|
builder.AppendLine("),");
|
||||||
|
builder.Append(" ");
|
||||||
|
builder.Append(implementationVariableName);
|
||||||
|
builder.AppendLine(");");
|
||||||
|
builder.Append(" logger.Debug(\"Registered CQRS handler ");
|
||||||
|
builder.Append(EscapeStringLiteral(registration.ImplementationLogName));
|
||||||
|
builder.Append(" as ");
|
||||||
|
builder.Append(EscapeStringLiteral(reflectedRegistration.HandlerInterfaceLogName));
|
||||||
|
builder.AppendLine(".\");");
|
||||||
|
}
|
||||||
|
|
||||||
|
builder.AppendLine(" }");
|
||||||
|
}
|
||||||
|
|
||||||
private static void AppendReflectionHelpers(StringBuilder builder)
|
private static void AppendReflectionHelpers(StringBuilder builder)
|
||||||
{
|
{
|
||||||
// Emit the runtime helper methods only when at least one handler requires metadata-name lookup.
|
// Emit the runtime helper methods only when at least one handler requires metadata-name lookup.
|
||||||
@ -523,10 +585,15 @@ public sealed class CqrsHandlerRegistryGenerator : IIncrementalGenerator
|
|||||||
string HandlerInterfaceLogName,
|
string HandlerInterfaceLogName,
|
||||||
string ImplementationLogName);
|
string ImplementationLogName);
|
||||||
|
|
||||||
|
private readonly record struct ReflectedImplementationRegistrationSpec(
|
||||||
|
string HandlerInterfaceDisplayName,
|
||||||
|
string HandlerInterfaceLogName);
|
||||||
|
|
||||||
private readonly record struct ImplementationRegistrationSpec(
|
private readonly record struct ImplementationRegistrationSpec(
|
||||||
string ImplementationTypeDisplayName,
|
string ImplementationTypeDisplayName,
|
||||||
string ImplementationLogName,
|
string ImplementationLogName,
|
||||||
ImmutableArray<HandlerRegistrationSpec> DirectRegistrations,
|
ImmutableArray<HandlerRegistrationSpec> DirectRegistrations,
|
||||||
|
ImmutableArray<ReflectedImplementationRegistrationSpec> ReflectedImplementationRegistrations,
|
||||||
string? ReflectionTypeMetadataName);
|
string? ReflectionTypeMetadataName);
|
||||||
|
|
||||||
private readonly struct HandlerCandidateAnalysis : IEquatable<HandlerCandidateAnalysis>
|
private readonly struct HandlerCandidateAnalysis : IEquatable<HandlerCandidateAnalysis>
|
||||||
@ -535,11 +602,13 @@ public sealed class CqrsHandlerRegistryGenerator : IIncrementalGenerator
|
|||||||
string implementationTypeDisplayName,
|
string implementationTypeDisplayName,
|
||||||
string implementationLogName,
|
string implementationLogName,
|
||||||
ImmutableArray<HandlerRegistrationSpec> registrations,
|
ImmutableArray<HandlerRegistrationSpec> registrations,
|
||||||
|
ImmutableArray<ReflectedImplementationRegistrationSpec> reflectedImplementationRegistrations,
|
||||||
string? reflectionTypeMetadataName)
|
string? reflectionTypeMetadataName)
|
||||||
{
|
{
|
||||||
ImplementationTypeDisplayName = implementationTypeDisplayName;
|
ImplementationTypeDisplayName = implementationTypeDisplayName;
|
||||||
ImplementationLogName = implementationLogName;
|
ImplementationLogName = implementationLogName;
|
||||||
Registrations = registrations;
|
Registrations = registrations;
|
||||||
|
ReflectedImplementationRegistrations = reflectedImplementationRegistrations;
|
||||||
ReflectionTypeMetadataName = reflectionTypeMetadataName;
|
ReflectionTypeMetadataName = reflectionTypeMetadataName;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -549,6 +618,8 @@ public sealed class CqrsHandlerRegistryGenerator : IIncrementalGenerator
|
|||||||
|
|
||||||
public ImmutableArray<HandlerRegistrationSpec> Registrations { get; }
|
public ImmutableArray<HandlerRegistrationSpec> Registrations { get; }
|
||||||
|
|
||||||
|
public ImmutableArray<ReflectedImplementationRegistrationSpec> ReflectedImplementationRegistrations { get; }
|
||||||
|
|
||||||
public string? ReflectionTypeMetadataName { get; }
|
public string? ReflectionTypeMetadataName { get; }
|
||||||
|
|
||||||
public bool Equals(HandlerCandidateAnalysis other)
|
public bool Equals(HandlerCandidateAnalysis other)
|
||||||
@ -558,7 +629,8 @@ public sealed class CqrsHandlerRegistryGenerator : IIncrementalGenerator
|
|||||||
!string.Equals(ImplementationLogName, other.ImplementationLogName, StringComparison.Ordinal) ||
|
!string.Equals(ImplementationLogName, other.ImplementationLogName, StringComparison.Ordinal) ||
|
||||||
!string.Equals(ReflectionTypeMetadataName, other.ReflectionTypeMetadataName,
|
!string.Equals(ReflectionTypeMetadataName, other.ReflectionTypeMetadataName,
|
||||||
StringComparison.Ordinal) ||
|
StringComparison.Ordinal) ||
|
||||||
Registrations.Length != other.Registrations.Length)
|
Registrations.Length != other.Registrations.Length ||
|
||||||
|
ReflectedImplementationRegistrations.Length != other.ReflectedImplementationRegistrations.Length)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -569,6 +641,13 @@ public sealed class CqrsHandlerRegistryGenerator : IIncrementalGenerator
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (var index = 0; index < ReflectedImplementationRegistrations.Length; index++)
|
||||||
|
{
|
||||||
|
if (!ReflectedImplementationRegistrations[index].Equals(
|
||||||
|
other.ReflectedImplementationRegistrations[index]))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -592,6 +671,11 @@ public sealed class CqrsHandlerRegistryGenerator : IIncrementalGenerator
|
|||||||
hashCode = (hashCode * 397) ^ registration.GetHashCode();
|
hashCode = (hashCode * 397) ^ registration.GetHashCode();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
foreach (var reflectedImplementationRegistration in ReflectedImplementationRegistrations)
|
||||||
|
{
|
||||||
|
hashCode = (hashCode * 397) ^ reflectedImplementationRegistration.GetHashCode();
|
||||||
|
}
|
||||||
|
|
||||||
return hashCode;
|
return hashCode;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user