mirror of
https://github.com/GeWuYou/GFramework.git
synced 2026-05-07 00:39:00 +08:00
feat(source-generators): 添加多个代码生成器功能
- 新增 PriorityGenerator 为标记 Priority 特性的类自动生成 IPrioritized 接口实现 - 新增 EnumExtensionsGenerator 为枚举自动生成 Is 和 IsIn 扩展方法 - 新增 LoggerGenerator 为标记 Log 特性的类自动生成日志字段 - 新增 ContextAwareGenerator 为标记 ContextAware 特性的类自动生成 IContextAware 接口实现 - 新增 CqrsHandlerRegistryGenerator 为 CQRS 处理器生成编译时注册器减少运行时反射开销
This commit is contained in:
parent
35a1634697
commit
b19877f970
@ -118,6 +118,9 @@ public sealed class PriorityGenerator : MetadataAttributeClassGeneratorBase
|
||||
? $"<{string.Join(", ", symbol.TypeParameters.Select(tp => tp.Name))}>"
|
||||
: string.Empty;
|
||||
|
||||
sb.AppendLine("/// <summary>");
|
||||
sb.AppendLine("/// 为当前分部类型补充自动生成的优先级契约实现。");
|
||||
sb.AppendLine("/// </summary>");
|
||||
sb.AppendLine(
|
||||
$"partial class {symbol.Name}{typeParameters} : global::GFramework.Core.Abstractions.Bases.IPrioritized");
|
||||
sb.AppendLine("{");
|
||||
|
||||
@ -95,6 +95,9 @@ public sealed class EnumExtensionsGenerator : AttributeEnumGeneratorBase
|
||||
|
||||
sb.AppendLine("{");
|
||||
|
||||
sb.AppendLine(" /// <summary>");
|
||||
sb.AppendLine($" /// 为 <see cref=\"{fullEnumName}\" /> 提供自动生成的扩展方法。");
|
||||
sb.AppendLine(" /// </summary>");
|
||||
sb.AppendLine($" public static partial class {enumName}Extensions");
|
||||
sb.AppendLine(" {");
|
||||
|
||||
@ -176,7 +179,13 @@ public sealed class EnumExtensionsGenerator : AttributeEnumGeneratorBase
|
||||
builder.AppendLine();
|
||||
}
|
||||
|
||||
builder.AppendLine($" /// <summary>是否为 {memberName}</summary>");
|
||||
builder.AppendLine(" /// <summary>");
|
||||
builder.AppendLine(
|
||||
$" /// 判断给定值是否为 <see cref=\"{fullEnumName}.{memberName}\" />。");
|
||||
builder.AppendLine(" /// </summary>");
|
||||
builder.AppendLine(" /// <param name=\"value\">要检查的枚举值。</param>");
|
||||
builder.AppendLine(
|
||||
$" /// <returns>当 <paramref name=\"value\" /> 等于 <see cref=\"{fullEnumName}.{memberName}\" /> 时返回 <see langword=\"true\" />;否则返回 <see langword=\"false\" />。</returns>");
|
||||
builder.AppendLine(
|
||||
$" public static bool Is{memberName}(this {fullEnumName} value) => value == {fullEnumName}.{memberName};");
|
||||
hasGeneratedMembers = true;
|
||||
@ -192,7 +201,13 @@ public sealed class EnumExtensionsGenerator : AttributeEnumGeneratorBase
|
||||
/// <param name="fullEnumName">枚举的完整类型名。</param>
|
||||
private static void AppendIsInMethod(StringBuilder builder, string fullEnumName)
|
||||
{
|
||||
builder.AppendLine(" /// <summary>判断是否属于指定集合</summary>");
|
||||
builder.AppendLine(" /// <summary>");
|
||||
builder.AppendLine(" /// 判断给定值是否属于指定候选集合。");
|
||||
builder.AppendLine(" /// </summary>");
|
||||
builder.AppendLine(" /// <param name=\"value\">要检查的枚举值。</param>");
|
||||
builder.AppendLine(" /// <param name=\"values\">用于匹配的候选枚举值集合。</param>");
|
||||
builder.AppendLine(
|
||||
" /// <returns>当 <paramref name=\"value\" /> 命中任一候选值时返回 <see langword=\"true\" />;否则返回 <see langword=\"false\" />。</returns>");
|
||||
builder.AppendLine(
|
||||
$" public static bool IsIn(this {fullEnumName} value, params {fullEnumName}[] values)");
|
||||
builder.AppendLine(" {");
|
||||
|
||||
@ -71,13 +71,18 @@ public sealed class LoggerGenerator : TypeAttributeClassGeneratorBase
|
||||
.AppendLine($"namespace {ns};");
|
||||
|
||||
sb.AppendLine()
|
||||
.AppendLine("/// <summary>")
|
||||
.AppendLine("/// 为当前分部类型提供自动生成的日志字段。")
|
||||
.AppendLine("/// </summary>")
|
||||
.AppendLine($"partial {typeKind} {className}{generics.Parameters}");
|
||||
|
||||
foreach (var c in generics.Constraints)
|
||||
sb.AppendLine($" {c}");
|
||||
|
||||
sb.AppendLine("{")
|
||||
.AppendLine(" /// <summary>Auto-generated logger</summary>")
|
||||
.AppendLine(" /// <summary>")
|
||||
.AppendLine(" /// 自动生成的日志字段。")
|
||||
.AppendLine(" /// </summary>")
|
||||
.AppendLine(
|
||||
$" {access} {staticKeyword}readonly ILogger {fieldName} = " +
|
||||
$"LoggerFactoryResolver.Provider.CreateLogger(\"{logName}\");")
|
||||
|
||||
@ -96,6 +96,9 @@ public sealed class ContextAwareGenerator : MetadataAttributeClassGeneratorBase
|
||||
|
||||
var interfaceName = iContextAware.ToDisplayString(
|
||||
SymbolDisplayFormat.FullyQualifiedFormat);
|
||||
sb.AppendLine("/// <summary>");
|
||||
sb.AppendLine("/// 为当前规则类型补充自动生成的架构上下文访问实现。");
|
||||
sb.AppendLine("/// </summary>");
|
||||
sb.AppendLine($"partial class {symbol.Name} : {interfaceName}");
|
||||
sb.AppendLine("{");
|
||||
|
||||
@ -128,6 +131,7 @@ public sealed class ContextAwareGenerator : MetadataAttributeClassGeneratorBase
|
||||
sb.AppendLine(" private global::GFramework.Core.Abstractions.Architectures.IArchitectureContext? _context;");
|
||||
sb.AppendLine(
|
||||
" private static global::GFramework.Core.Abstractions.Architectures.IArchitectureContextProvider? _contextProvider;");
|
||||
sb.AppendLine(" private static readonly object _contextSync = new();");
|
||||
sb.AppendLine();
|
||||
sb.AppendLine(" /// <summary>");
|
||||
sb.AppendLine(" /// 自动获取的架构上下文(懒加载,默认使用 GameContextProvider)");
|
||||
@ -136,14 +140,20 @@ public sealed class ContextAwareGenerator : MetadataAttributeClassGeneratorBase
|
||||
sb.AppendLine(" {");
|
||||
sb.AppendLine(" get");
|
||||
sb.AppendLine(" {");
|
||||
sb.AppendLine(" if (_context == null)");
|
||||
sb.AppendLine(" var context = _context;");
|
||||
sb.AppendLine(" if (context is not null)");
|
||||
sb.AppendLine(" {");
|
||||
sb.AppendLine(" return context;");
|
||||
sb.AppendLine(" }");
|
||||
sb.AppendLine();
|
||||
sb.AppendLine(" // 在同一个同步域内协调懒加载与 provider 切换,避免读取到被并发重置的空提供者。");
|
||||
sb.AppendLine(" lock (_contextSync)");
|
||||
sb.AppendLine(" {");
|
||||
sb.AppendLine(
|
||||
" _contextProvider ??= new global::GFramework.Core.Architectures.GameContextProvider();");
|
||||
sb.AppendLine(" _context = _contextProvider.GetContext();");
|
||||
sb.AppendLine(" _context ??= _contextProvider.GetContext();");
|
||||
sb.AppendLine(" return _context;");
|
||||
sb.AppendLine(" }");
|
||||
sb.AppendLine();
|
||||
sb.AppendLine(" return _context;");
|
||||
sb.AppendLine(" }");
|
||||
sb.AppendLine(" }");
|
||||
sb.AppendLine();
|
||||
@ -154,7 +164,10 @@ public sealed class ContextAwareGenerator : MetadataAttributeClassGeneratorBase
|
||||
sb.AppendLine(
|
||||
" public static void SetContextProvider(global::GFramework.Core.Abstractions.Architectures.IArchitectureContextProvider provider)");
|
||||
sb.AppendLine(" {");
|
||||
sb.AppendLine(" _contextProvider = provider;");
|
||||
sb.AppendLine(" lock (_contextSync)");
|
||||
sb.AppendLine(" {");
|
||||
sb.AppendLine(" _contextProvider = provider;");
|
||||
sb.AppendLine(" }");
|
||||
sb.AppendLine(" }");
|
||||
sb.AppendLine();
|
||||
sb.AppendLine(" /// <summary>");
|
||||
@ -162,7 +175,10 @@ public sealed class ContextAwareGenerator : MetadataAttributeClassGeneratorBase
|
||||
sb.AppendLine(" /// </summary>");
|
||||
sb.AppendLine(" public static void ResetContextProvider()");
|
||||
sb.AppendLine(" {");
|
||||
sb.AppendLine(" _contextProvider = null;");
|
||||
sb.AppendLine(" lock (_contextSync)");
|
||||
sb.AppendLine(" {");
|
||||
sb.AppendLine(" _contextProvider = null;");
|
||||
sb.AppendLine(" }");
|
||||
sb.AppendLine(" }");
|
||||
sb.AppendLine();
|
||||
}
|
||||
|
||||
@ -165,8 +165,9 @@ public sealed class CqrsHandlerRegistryGenerator : IIncrementalGenerator
|
||||
.Cast<string>()
|
||||
.ToArray();
|
||||
|
||||
if (fallbackHandlerTypeMetadataNames.Length > 0 &&
|
||||
!generationEnvironment.SupportsReflectionFallbackAttribute)
|
||||
if (!CanEmitGeneratedRegistry(
|
||||
generationEnvironment.SupportsReflectionFallbackAttribute,
|
||||
fallbackHandlerTypeMetadataNames.Length))
|
||||
{
|
||||
return;
|
||||
}
|
||||
@ -176,6 +177,26 @@ public sealed class CqrsHandlerRegistryGenerator : IIncrementalGenerator
|
||||
GenerateSource(generationEnvironment, registrations, fallbackHandlerTypeMetadataNames));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 判断当前轮次是否允许输出生成注册器。
|
||||
/// </summary>
|
||||
/// <param name="supportsReflectionFallbackAttribute">
|
||||
/// runtime 合同中是否存在 <c>CqrsReflectionFallbackAttribute</c>,以承载生成器无法静态精确表达的 handler 回退元数据。
|
||||
/// </param>
|
||||
/// <param name="fallbackHandlerTypeCount">
|
||||
/// 当前轮次需要依赖程序集级 reflection fallback 元数据恢复的 handler 数量。
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// 当没有 handler 依赖 fallback,或 runtime 已提供承载该元数据的特性契约时返回 <see langword="true" />;
|
||||
/// 否则返回 <see langword="false" />,调用方必须放弃生成以避免输出会静默漏注册的半成品注册器。
|
||||
/// </returns>
|
||||
private static bool CanEmitGeneratedRegistry(
|
||||
bool supportsReflectionFallbackAttribute,
|
||||
int fallbackHandlerTypeCount)
|
||||
{
|
||||
return fallbackHandlerTypeCount == 0 || supportsReflectionFallbackAttribute;
|
||||
}
|
||||
|
||||
private static List<ImplementationRegistrationSpec> CollectRegistrations(
|
||||
ImmutableArray<HandlerCandidateAnalysis?> candidates)
|
||||
{
|
||||
|
||||
@ -3,10 +3,13 @@
|
||||
|
||||
namespace TestApp;
|
||||
|
||||
/// <summary>
|
||||
/// 为当前分部类型补充自动生成的优先级契约实现。
|
||||
/// </summary>
|
||||
partial class MySystem : global::GFramework.Core.Abstractions.Bases.IPrioritized
|
||||
{
|
||||
/// <summary>
|
||||
/// 获取优先级值: 10
|
||||
/// </summary>
|
||||
public int Priority => 10;
|
||||
}
|
||||
}
|
||||
|
||||
@ -3,10 +3,13 @@
|
||||
|
||||
namespace TestApp;
|
||||
|
||||
/// <summary>
|
||||
/// 为当前分部类型补充自动生成的优先级契约实现。
|
||||
/// </summary>
|
||||
partial class GenericSystem<T> : global::GFramework.Core.Abstractions.Bases.IPrioritized
|
||||
{
|
||||
/// <summary>
|
||||
/// 获取优先级值: 20
|
||||
/// </summary>
|
||||
public int Priority => 20;
|
||||
}
|
||||
}
|
||||
|
||||
@ -3,10 +3,13 @@
|
||||
|
||||
namespace TestApp;
|
||||
|
||||
/// <summary>
|
||||
/// 为当前分部类型补充自动生成的优先级契约实现。
|
||||
/// </summary>
|
||||
partial class CriticalSystem : global::GFramework.Core.Abstractions.Bases.IPrioritized
|
||||
{
|
||||
/// <summary>
|
||||
/// 获取优先级值: -100
|
||||
/// </summary>
|
||||
public int Priority => -100;
|
||||
}
|
||||
}
|
||||
|
||||
@ -3,10 +3,13 @@
|
||||
|
||||
namespace TestApp;
|
||||
|
||||
/// <summary>
|
||||
/// 为当前分部类型补充自动生成的优先级契约实现。
|
||||
/// </summary>
|
||||
partial class HighPrioritySystem : global::GFramework.Core.Abstractions.Bases.IPrioritized
|
||||
{
|
||||
/// <summary>
|
||||
/// 获取优先级值: -50
|
||||
/// </summary>
|
||||
public int Priority => -50;
|
||||
}
|
||||
}
|
||||
|
||||
@ -42,7 +42,7 @@ public static class GeneratorSnapshotTest<TGenerator>
|
||||
compilationErrors,
|
||||
Is.Empty,
|
||||
() =>
|
||||
$"编译生成的代码时出现错误:{Environment.NewLine}{string.Join(Environment.NewLine, compilationErrors.Select(static diagnostic => diagnostic.ToString()))}");
|
||||
$"编译生成的代码时出现错误:{Environment.NewLine}{string.Join(Environment.NewLine, compilationErrors.Select(static diagnostic => diagnostic.ToString()))}");
|
||||
|
||||
var runResult = driver.GetRunResult();
|
||||
var generated = runResult.Results
|
||||
@ -53,7 +53,7 @@ public static class GeneratorSnapshotTest<TGenerator>
|
||||
Assert.That(
|
||||
generated,
|
||||
Is.Not.Empty,
|
||||
$"Generator '{typeof(TGenerator).FullName}' did not produce any sources.");
|
||||
$"生成器 '{typeof(TGenerator).FullName}' 未产生任何输出。");
|
||||
|
||||
foreach (var (filename, content) in generated)
|
||||
{
|
||||
@ -70,7 +70,7 @@ public static class GeneratorSnapshotTest<TGenerator>
|
||||
await File.WriteAllTextAsync(path, content.ToString());
|
||||
|
||||
Assert.Fail(
|
||||
$"Snapshot not found. Generated new snapshot at:\n{path}");
|
||||
$"未找到快照文件,已在以下路径生成新快照:\n{path}");
|
||||
}
|
||||
|
||||
var expected = await File.ReadAllTextAsync(path);
|
||||
@ -78,7 +78,7 @@ public static class GeneratorSnapshotTest<TGenerator>
|
||||
Assert.That(
|
||||
Normalize(expected),
|
||||
Is.EqualTo(Normalize(content.ToString())),
|
||||
$"Snapshot mismatch: {snapshotFileName}");
|
||||
$"快照不匹配:{snapshotFileName}");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1168,6 +1168,32 @@ public class CqrsHandlerRegistryGeneratorTests
|
||||
("CqrsHandlerRegistry.g.cs", HiddenNestedHandlerSelfRegistrationExpected));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 验证当某轮生成仍然需要程序集级 reflection fallback 元数据时,
|
||||
/// 若 runtime 合同未提供对应特性契约,生成器会放弃输出注册器以避免静默漏注册。
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void
|
||||
Rejects_Registry_Emission_When_Fallback_Metadata_Is_Required_But_Runtime_Contract_Lacks_Fallback_Attribute()
|
||||
{
|
||||
var method = typeof(CqrsHandlerRegistryGenerator).GetMethod(
|
||||
"CanEmitGeneratedRegistry",
|
||||
BindingFlags.NonPublic | BindingFlags.Static);
|
||||
|
||||
Assert.That(method, Is.Not.Null);
|
||||
|
||||
var canEmitWithoutFallbackRequirement = (bool?)method!.Invoke(null, [false, 0]);
|
||||
var canEmitWithSupportedFallbackAttribute = (bool?)method.Invoke(null, [true, 1]);
|
||||
var canEmitWithoutSupportedFallbackAttribute = (bool?)method.Invoke(null, [false, 1]);
|
||||
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.That(canEmitWithoutFallbackRequirement, Is.True);
|
||||
Assert.That(canEmitWithSupportedFallbackAttribute, Is.True);
|
||||
Assert.That(canEmitWithoutSupportedFallbackAttribute, Is.False);
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 验证日志字符串转义会覆盖换行、反斜杠和双引号,避免生成代码中的字符串字面量被意外截断。
|
||||
/// </summary>
|
||||
|
||||
@ -15,6 +15,7 @@ public class EnumExtensionsGeneratorSnapshotTests
|
||||
/// <summary>
|
||||
/// 验证默认配置会为普通枚举生成逐项判断方法与集合判断方法。
|
||||
/// </summary>
|
||||
/// <returns>异步任务。</returns>
|
||||
[Test]
|
||||
public async Task Snapshot_BasicEnum_IsMethods()
|
||||
{
|
||||
@ -37,6 +38,7 @@ public class EnumExtensionsGeneratorSnapshotTests
|
||||
/// <summary>
|
||||
/// 验证未提供快照文件名映射时,会直接按生成文件名进行快照比对。
|
||||
/// </summary>
|
||||
/// <returns>异步任务。</returns>
|
||||
[Test]
|
||||
public async Task Snapshot_BasicEnum_IsMethods_DefaultSnapshotFileNameSelector()
|
||||
{
|
||||
@ -57,6 +59,7 @@ public class EnumExtensionsGeneratorSnapshotTests
|
||||
/// <summary>
|
||||
/// 验证默认配置在较小枚举上仍会生成集合判断方法。
|
||||
/// </summary>
|
||||
/// <returns>异步任务。</returns>
|
||||
[Test]
|
||||
public async Task Snapshot_BasicEnum_IsInMethod()
|
||||
{
|
||||
@ -78,6 +81,7 @@ public class EnumExtensionsGeneratorSnapshotTests
|
||||
/// <summary>
|
||||
/// 验证带显式位标志值的枚举也会生成对应扩展方法。
|
||||
/// </summary>
|
||||
/// <returns>异步任务。</returns>
|
||||
[Test]
|
||||
public async Task Snapshot_EnumWithFlagValues()
|
||||
{
|
||||
@ -102,6 +106,7 @@ public class EnumExtensionsGeneratorSnapshotTests
|
||||
/// <summary>
|
||||
/// 验证关闭逐项判断开关后仅保留集合判断方法。
|
||||
/// </summary>
|
||||
/// <returns>异步任务。</returns>
|
||||
[Test]
|
||||
public async Task Snapshot_DisableIsMethods()
|
||||
{
|
||||
@ -124,6 +129,7 @@ public class EnumExtensionsGeneratorSnapshotTests
|
||||
/// <summary>
|
||||
/// 验证关闭集合判断开关后仅保留逐项判断方法。
|
||||
/// </summary>
|
||||
/// <returns>异步任务。</returns>
|
||||
[Test]
|
||||
public async Task Snapshot_DisableIsInMethod()
|
||||
{
|
||||
@ -146,6 +152,7 @@ public class EnumExtensionsGeneratorSnapshotTests
|
||||
/// <summary>
|
||||
/// 验证同时关闭两个生成开关时不会输出任何扩展方法。
|
||||
/// </summary>
|
||||
/// <returns>异步任务。</returns>
|
||||
[Test]
|
||||
public async Task Snapshot_DisableAllGeneratedMethods()
|
||||
{
|
||||
|
||||
@ -2,15 +2,31 @@
|
||||
using System;
|
||||
namespace TestApp
|
||||
{
|
||||
/// <summary>
|
||||
/// 为 <see cref="TestApp.Status" /> 提供自动生成的扩展方法。
|
||||
/// </summary>
|
||||
public static partial class StatusExtensions
|
||||
{
|
||||
/// <summary>是否为 Active</summary>
|
||||
/// <summary>
|
||||
/// 判断给定值是否为 <see cref="TestApp.Status.Active" />。
|
||||
/// </summary>
|
||||
/// <param name="value">要检查的枚举值。</param>
|
||||
/// <returns>当 <paramref name="value" /> 等于 <see cref="TestApp.Status.Active" /> 时返回 <see langword="true" />;否则返回 <see langword="false" />。</returns>
|
||||
public static bool IsActive(this TestApp.Status value) => value == TestApp.Status.Active;
|
||||
|
||||
/// <summary>是否为 Inactive</summary>
|
||||
/// <summary>
|
||||
/// 判断给定值是否为 <see cref="TestApp.Status.Inactive" />。
|
||||
/// </summary>
|
||||
/// <param name="value">要检查的枚举值。</param>
|
||||
/// <returns>当 <paramref name="value" /> 等于 <see cref="TestApp.Status.Inactive" /> 时返回 <see langword="true" />;否则返回 <see langword="false" />。</returns>
|
||||
public static bool IsInactive(this TestApp.Status value) => value == TestApp.Status.Inactive;
|
||||
|
||||
/// <summary>判断是否属于指定集合</summary>
|
||||
/// <summary>
|
||||
/// 判断给定值是否属于指定候选集合。
|
||||
/// </summary>
|
||||
/// <param name="value">要检查的枚举值。</param>
|
||||
/// <param name="values">用于匹配的候选枚举值集合。</param>
|
||||
/// <returns>当 <paramref name="value" /> 命中任一候选值时返回 <see langword="true" />;否则返回 <see langword="false" />。</returns>
|
||||
public static bool IsIn(this TestApp.Status value, params TestApp.Status[] values)
|
||||
{
|
||||
if (values == null) return false;
|
||||
|
||||
@ -2,18 +2,38 @@
|
||||
using System;
|
||||
namespace TestApp
|
||||
{
|
||||
/// <summary>
|
||||
/// 为 <see cref="TestApp.Status" /> 提供自动生成的扩展方法。
|
||||
/// </summary>
|
||||
public static partial class StatusExtensions
|
||||
{
|
||||
/// <summary>是否为 Active</summary>
|
||||
/// <summary>
|
||||
/// 判断给定值是否为 <see cref="TestApp.Status.Active" />。
|
||||
/// </summary>
|
||||
/// <param name="value">要检查的枚举值。</param>
|
||||
/// <returns>当 <paramref name="value" /> 等于 <see cref="TestApp.Status.Active" /> 时返回 <see langword="true" />;否则返回 <see langword="false" />。</returns>
|
||||
public static bool IsActive(this TestApp.Status value) => value == TestApp.Status.Active;
|
||||
|
||||
/// <summary>是否为 Inactive</summary>
|
||||
/// <summary>
|
||||
/// 判断给定值是否为 <see cref="TestApp.Status.Inactive" />。
|
||||
/// </summary>
|
||||
/// <param name="value">要检查的枚举值。</param>
|
||||
/// <returns>当 <paramref name="value" /> 等于 <see cref="TestApp.Status.Inactive" /> 时返回 <see langword="true" />;否则返回 <see langword="false" />。</returns>
|
||||
public static bool IsInactive(this TestApp.Status value) => value == TestApp.Status.Inactive;
|
||||
|
||||
/// <summary>是否为 Pending</summary>
|
||||
/// <summary>
|
||||
/// 判断给定值是否为 <see cref="TestApp.Status.Pending" />。
|
||||
/// </summary>
|
||||
/// <param name="value">要检查的枚举值。</param>
|
||||
/// <returns>当 <paramref name="value" /> 等于 <see cref="TestApp.Status.Pending" /> 时返回 <see langword="true" />;否则返回 <see langword="false" />。</returns>
|
||||
public static bool IsPending(this TestApp.Status value) => value == TestApp.Status.Pending;
|
||||
|
||||
/// <summary>判断是否属于指定集合</summary>
|
||||
/// <summary>
|
||||
/// 判断给定值是否属于指定候选集合。
|
||||
/// </summary>
|
||||
/// <param name="value">要检查的枚举值。</param>
|
||||
/// <param name="values">用于匹配的候选枚举值集合。</param>
|
||||
/// <returns>当 <paramref name="value" /> 命中任一候选值时返回 <see langword="true" />;否则返回 <see langword="false" />。</returns>
|
||||
public static bool IsIn(this TestApp.Status value, params TestApp.Status[] values)
|
||||
{
|
||||
if (values == null) return false;
|
||||
|
||||
@ -2,15 +2,31 @@
|
||||
using System;
|
||||
namespace TestApp
|
||||
{
|
||||
/// <summary>
|
||||
/// 为 <see cref="TestApp.Status" /> 提供自动生成的扩展方法。
|
||||
/// </summary>
|
||||
public static partial class StatusExtensions
|
||||
{
|
||||
/// <summary>是否为 Active</summary>
|
||||
/// <summary>
|
||||
/// 判断给定值是否为 <see cref="TestApp.Status.Active" />。
|
||||
/// </summary>
|
||||
/// <param name="value">要检查的枚举值。</param>
|
||||
/// <returns>当 <paramref name="value" /> 等于 <see cref="TestApp.Status.Active" /> 时返回 <see langword="true" />;否则返回 <see langword="false" />。</returns>
|
||||
public static bool IsActive(this TestApp.Status value) => value == TestApp.Status.Active;
|
||||
|
||||
/// <summary>是否为 Inactive</summary>
|
||||
/// <summary>
|
||||
/// 判断给定值是否为 <see cref="TestApp.Status.Inactive" />。
|
||||
/// </summary>
|
||||
/// <param name="value">要检查的枚举值。</param>
|
||||
/// <returns>当 <paramref name="value" /> 等于 <see cref="TestApp.Status.Inactive" /> 时返回 <see langword="true" />;否则返回 <see langword="false" />。</returns>
|
||||
public static bool IsInactive(this TestApp.Status value) => value == TestApp.Status.Inactive;
|
||||
|
||||
/// <summary>判断是否属于指定集合</summary>
|
||||
/// <summary>
|
||||
/// 判断给定值是否属于指定候选集合。
|
||||
/// </summary>
|
||||
/// <param name="value">要检查的枚举值。</param>
|
||||
/// <param name="values">用于匹配的候选枚举值集合。</param>
|
||||
/// <returns>当 <paramref name="value" /> 命中任一候选值时返回 <see langword="true" />;否则返回 <see langword="false" />。</returns>
|
||||
public static bool IsIn(this TestApp.Status value, params TestApp.Status[] values)
|
||||
{
|
||||
if (values == null) return false;
|
||||
|
||||
@ -2,6 +2,9 @@
|
||||
using System;
|
||||
namespace TestApp
|
||||
{
|
||||
/// <summary>
|
||||
/// 为 <see cref="TestApp.Status" /> 提供自动生成的扩展方法。
|
||||
/// </summary>
|
||||
public static partial class StatusExtensions
|
||||
{
|
||||
}
|
||||
|
||||
@ -2,12 +2,23 @@
|
||||
using System;
|
||||
namespace TestApp
|
||||
{
|
||||
/// <summary>
|
||||
/// 为 <see cref="TestApp.Status" /> 提供自动生成的扩展方法。
|
||||
/// </summary>
|
||||
public static partial class StatusExtensions
|
||||
{
|
||||
/// <summary>是否为 Active</summary>
|
||||
/// <summary>
|
||||
/// 判断给定值是否为 <see cref="TestApp.Status.Active" />。
|
||||
/// </summary>
|
||||
/// <param name="value">要检查的枚举值。</param>
|
||||
/// <returns>当 <paramref name="value" /> 等于 <see cref="TestApp.Status.Active" /> 时返回 <see langword="true" />;否则返回 <see langword="false" />。</returns>
|
||||
public static bool IsActive(this TestApp.Status value) => value == TestApp.Status.Active;
|
||||
|
||||
/// <summary>是否为 Inactive</summary>
|
||||
/// <summary>
|
||||
/// 判断给定值是否为 <see cref="TestApp.Status.Inactive" />。
|
||||
/// </summary>
|
||||
/// <param name="value">要检查的枚举值。</param>
|
||||
/// <returns>当 <paramref name="value" /> 等于 <see cref="TestApp.Status.Inactive" /> 时返回 <see langword="true" />;否则返回 <see langword="false" />。</returns>
|
||||
public static bool IsInactive(this TestApp.Status value) => value == TestApp.Status.Inactive;
|
||||
}
|
||||
}
|
||||
|
||||
@ -2,9 +2,17 @@
|
||||
using System;
|
||||
namespace TestApp
|
||||
{
|
||||
/// <summary>
|
||||
/// 为 <see cref="TestApp.Status" /> 提供自动生成的扩展方法。
|
||||
/// </summary>
|
||||
public static partial class StatusExtensions
|
||||
{
|
||||
/// <summary>判断是否属于指定集合</summary>
|
||||
/// <summary>
|
||||
/// 判断给定值是否属于指定候选集合。
|
||||
/// </summary>
|
||||
/// <param name="value">要检查的枚举值。</param>
|
||||
/// <param name="values">用于匹配的候选枚举值集合。</param>
|
||||
/// <returns>当 <paramref name="value" /> 命中任一候选值时返回 <see langword="true" />;否则返回 <see langword="false" />。</returns>
|
||||
public static bool IsIn(this TestApp.Status value, params TestApp.Status[] values)
|
||||
{
|
||||
if (values == null) return false;
|
||||
|
||||
@ -2,21 +2,45 @@
|
||||
using System;
|
||||
namespace TestApp
|
||||
{
|
||||
/// <summary>
|
||||
/// 为 <see cref="TestApp.Permissions" /> 提供自动生成的扩展方法。
|
||||
/// </summary>
|
||||
public static partial class PermissionsExtensions
|
||||
{
|
||||
/// <summary>是否为 None</summary>
|
||||
/// <summary>
|
||||
/// 判断给定值是否为 <see cref="TestApp.Permissions.None" />。
|
||||
/// </summary>
|
||||
/// <param name="value">要检查的枚举值。</param>
|
||||
/// <returns>当 <paramref name="value" /> 等于 <see cref="TestApp.Permissions.None" /> 时返回 <see langword="true" />;否则返回 <see langword="false" />。</returns>
|
||||
public static bool IsNone(this TestApp.Permissions value) => value == TestApp.Permissions.None;
|
||||
|
||||
/// <summary>是否为 Read</summary>
|
||||
/// <summary>
|
||||
/// 判断给定值是否为 <see cref="TestApp.Permissions.Read" />。
|
||||
/// </summary>
|
||||
/// <param name="value">要检查的枚举值。</param>
|
||||
/// <returns>当 <paramref name="value" /> 等于 <see cref="TestApp.Permissions.Read" /> 时返回 <see langword="true" />;否则返回 <see langword="false" />。</returns>
|
||||
public static bool IsRead(this TestApp.Permissions value) => value == TestApp.Permissions.Read;
|
||||
|
||||
/// <summary>是否为 Write</summary>
|
||||
/// <summary>
|
||||
/// 判断给定值是否为 <see cref="TestApp.Permissions.Write" />。
|
||||
/// </summary>
|
||||
/// <param name="value">要检查的枚举值。</param>
|
||||
/// <returns>当 <paramref name="value" /> 等于 <see cref="TestApp.Permissions.Write" /> 时返回 <see langword="true" />;否则返回 <see langword="false" />。</returns>
|
||||
public static bool IsWrite(this TestApp.Permissions value) => value == TestApp.Permissions.Write;
|
||||
|
||||
/// <summary>是否为 Execute</summary>
|
||||
/// <summary>
|
||||
/// 判断给定值是否为 <see cref="TestApp.Permissions.Execute" />。
|
||||
/// </summary>
|
||||
/// <param name="value">要检查的枚举值。</param>
|
||||
/// <returns>当 <paramref name="value" /> 等于 <see cref="TestApp.Permissions.Execute" /> 时返回 <see langword="true" />;否则返回 <see langword="false" />。</returns>
|
||||
public static bool IsExecute(this TestApp.Permissions value) => value == TestApp.Permissions.Execute;
|
||||
|
||||
/// <summary>判断是否属于指定集合</summary>
|
||||
/// <summary>
|
||||
/// 判断给定值是否属于指定候选集合。
|
||||
/// </summary>
|
||||
/// <param name="value">要检查的枚举值。</param>
|
||||
/// <param name="values">用于匹配的候选枚举值集合。</param>
|
||||
/// <returns>当 <paramref name="value" /> 命中任一候选值时返回 <see langword="true" />;否则返回 <see langword="false" />。</returns>
|
||||
public static bool IsIn(this TestApp.Permissions value, params TestApp.Permissions[] values)
|
||||
{
|
||||
if (values == null) return false;
|
||||
|
||||
@ -4,8 +4,13 @@ using GFramework.Core.Logging;
|
||||
|
||||
namespace TestApp;
|
||||
|
||||
/// <summary>
|
||||
/// 为当前分部类型提供自动生成的日志字段。
|
||||
/// </summary>
|
||||
partial class MyService
|
||||
{
|
||||
/// <summary>Auto-generated logger</summary>
|
||||
/// <summary>
|
||||
/// 自动生成的日志字段。
|
||||
/// </summary>
|
||||
private static readonly ILogger MyLogger = LoggerFactoryResolver.Provider.CreateLogger("MyService");
|
||||
}
|
||||
|
||||
@ -4,8 +4,13 @@ using GFramework.Core.Logging;
|
||||
|
||||
namespace TestApp;
|
||||
|
||||
/// <summary>
|
||||
/// 为当前分部类型提供自动生成的日志字段。
|
||||
/// </summary>
|
||||
partial class MyService
|
||||
{
|
||||
/// <summary>Auto-generated logger</summary>
|
||||
/// <summary>
|
||||
/// 自动生成的日志字段。
|
||||
/// </summary>
|
||||
private static readonly ILogger _log = LoggerFactoryResolver.Provider.CreateLogger("MyService");
|
||||
}
|
||||
|
||||
@ -4,8 +4,13 @@ using GFramework.Core.Logging;
|
||||
|
||||
namespace TestApp;
|
||||
|
||||
/// <summary>
|
||||
/// 为当前分部类型提供自动生成的日志字段。
|
||||
/// </summary>
|
||||
partial class MyService
|
||||
{
|
||||
/// <summary>Auto-generated logger</summary>
|
||||
/// <summary>
|
||||
/// 自动生成的日志字段。
|
||||
/// </summary>
|
||||
private static readonly ILogger _log = LoggerFactoryResolver.Provider.CreateLogger("MyService");
|
||||
}
|
||||
|
||||
@ -4,8 +4,13 @@ using GFramework.Core.Logging;
|
||||
|
||||
namespace TestApp;
|
||||
|
||||
/// <summary>
|
||||
/// 为当前分部类型提供自动生成的日志字段。
|
||||
/// </summary>
|
||||
partial class MyService<T>
|
||||
{
|
||||
/// <summary>Auto-generated logger</summary>
|
||||
/// <summary>
|
||||
/// 自动生成的日志字段。
|
||||
/// </summary>
|
||||
private static readonly ILogger _log = LoggerFactoryResolver.Provider.CreateLogger("MyService");
|
||||
}
|
||||
|
||||
@ -4,8 +4,13 @@ using GFramework.Core.Logging;
|
||||
|
||||
namespace TestApp;
|
||||
|
||||
/// <summary>
|
||||
/// 为当前分部类型提供自动生成的日志字段。
|
||||
/// </summary>
|
||||
partial class MyService
|
||||
{
|
||||
/// <summary>Auto-generated logger</summary>
|
||||
/// <summary>
|
||||
/// 自动生成的日志字段。
|
||||
/// </summary>
|
||||
private readonly ILogger _log = LoggerFactoryResolver.Provider.CreateLogger("MyService");
|
||||
}
|
||||
|
||||
@ -4,8 +4,13 @@ using GFramework.Core.Logging;
|
||||
|
||||
namespace TestApp;
|
||||
|
||||
/// <summary>
|
||||
/// 为当前分部类型提供自动生成的日志字段。
|
||||
/// </summary>
|
||||
partial class MyService
|
||||
{
|
||||
/// <summary>Auto-generated logger</summary>
|
||||
/// <summary>
|
||||
/// 自动生成的日志字段。
|
||||
/// </summary>
|
||||
public static readonly ILogger _log = LoggerFactoryResolver.Provider.CreateLogger("MyService");
|
||||
}
|
||||
|
||||
@ -3,10 +3,14 @@
|
||||
|
||||
namespace TestApp;
|
||||
|
||||
/// <summary>
|
||||
/// 为当前规则类型补充自动生成的架构上下文访问实现。
|
||||
/// </summary>
|
||||
partial class MyRule : global::GFramework.Core.Abstractions.Rule.IContextAware
|
||||
{
|
||||
private global::GFramework.Core.Abstractions.Architectures.IArchitectureContext? _context;
|
||||
private static global::GFramework.Core.Abstractions.Architectures.IArchitectureContextProvider? _contextProvider;
|
||||
private static readonly object _contextSync = new();
|
||||
|
||||
/// <summary>
|
||||
/// 自动获取的架构上下文(懒加载,默认使用 GameContextProvider)
|
||||
@ -15,13 +19,19 @@ partial class MyRule : global::GFramework.Core.Abstractions.Rule.IContextAware
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_context == null)
|
||||
var context = _context;
|
||||
if (context is not null)
|
||||
{
|
||||
_contextProvider ??= new global::GFramework.Core.Architectures.GameContextProvider();
|
||||
_context = _contextProvider.GetContext();
|
||||
return context;
|
||||
}
|
||||
|
||||
return _context;
|
||||
// 在同一个同步域内协调懒加载与 provider 切换,避免读取到被并发重置的空提供者。
|
||||
lock (_contextSync)
|
||||
{
|
||||
_contextProvider ??= new global::GFramework.Core.Architectures.GameContextProvider();
|
||||
_context ??= _contextProvider.GetContext();
|
||||
return _context;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -31,7 +41,10 @@ partial class MyRule : global::GFramework.Core.Abstractions.Rule.IContextAware
|
||||
/// <param name="provider">上下文提供者实例</param>
|
||||
public static void SetContextProvider(global::GFramework.Core.Abstractions.Architectures.IArchitectureContextProvider provider)
|
||||
{
|
||||
_contextProvider = provider;
|
||||
lock (_contextSync)
|
||||
{
|
||||
_contextProvider = provider;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -39,7 +52,10 @@ partial class MyRule : global::GFramework.Core.Abstractions.Rule.IContextAware
|
||||
/// </summary>
|
||||
public static void ResetContextProvider()
|
||||
{
|
||||
_contextProvider = null;
|
||||
lock (_contextSync)
|
||||
{
|
||||
_contextProvider = null;
|
||||
}
|
||||
}
|
||||
|
||||
void global::GFramework.Core.Abstractions.Rule.IContextAware.SetContext(global::GFramework.Core.Abstractions.Architectures.IArchitectureContext context)
|
||||
@ -52,4 +68,4 @@ partial class MyRule : global::GFramework.Core.Abstractions.Rule.IContextAware
|
||||
return Context;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user