refactor(core): 收敛 Core 扩展与测试的机械 warning

- 更新 ContextAware、Store 与通用扩展中的参数空校验写法以满足 analyzer 约束

- 简化 coroutine、pause、log 与 async 测试中的等待和断言包装并保持测试语义不变

- 调整测试替身异常类型与 Result 系列断言样例以减少低风险 warning 噪音
This commit is contained in:
gewuyou 2026-04-25 10:38:48 +08:00
parent 03c73a8ee5
commit 9ce1fa630c
22 changed files with 411 additions and 191 deletions

View File

@ -174,8 +174,15 @@ internal sealed class AdditionalAssemblyNotificationHandlerRegistry : ICqrsHandl
/// </exception> /// </exception>
public void Register(IServiceCollection services, ILogger logger) public void Register(IServiceCollection services, ILogger logger)
{ {
ArgumentNullException.ThrowIfNull(services); if (services is null)
ArgumentNullException.ThrowIfNull(logger); {
throw new ArgumentNullException(nameof(services));
}
if (logger is null)
{
throw new ArgumentNullException(nameof(logger));
}
services.AddTransient<INotificationHandler<AdditionalAssemblyNotification>>(_ => CreateHandler()); services.AddTransient<INotificationHandler<AdditionalAssemblyNotification>>(_ => CreateHandler());
logger.Debug( logger.Debug(

View File

@ -168,52 +168,52 @@ public class TestArchitectureWithRegistry : IArchitecture
T IArchitecture.RegisterSystem<T>(T system) T IArchitecture.RegisterSystem<T>(T system)
{ {
throw new NotImplementedException(); throw new NotSupportedException();
} }
T IArchitecture.RegisterModel<T>(T model) T IArchitecture.RegisterModel<T>(T model)
{ {
throw new NotImplementedException(); throw new NotSupportedException();
} }
T IArchitecture.RegisterUtility<T>(T utility) T IArchitecture.RegisterUtility<T>(T utility)
{ {
throw new NotImplementedException(); throw new NotSupportedException();
} }
public void RegisterCqrsPipelineBehavior<TBehavior>() where TBehavior : class public void RegisterCqrsPipelineBehavior<TBehavior>() where TBehavior : class
{ {
throw new NotImplementedException(); throw new NotSupportedException();
} }
/// <summary> /// <summary>
/// 测试替身未实现显式程序集 CQRS 处理器接入入口。 /// 测试替身未实现显式程序集 CQRS 处理器接入入口。
/// </summary> /// </summary>
/// <param name="assembly">包含 CQRS 处理器或生成注册器的程序集。</param> /// <param name="assembly">包含 CQRS 处理器或生成注册器的程序集。</param>
/// <exception cref="NotImplementedException">该测试替身不参与 CQRS 程序集接入路径验证。</exception> /// <exception cref="NotSupportedException">该测试替身不参与 CQRS 程序集接入路径验证。</exception>
public void RegisterCqrsHandlersFromAssembly(Assembly assembly) public void RegisterCqrsHandlersFromAssembly(Assembly assembly)
{ {
throw new NotImplementedException(); throw new NotSupportedException();
} }
/// <summary> /// <summary>
/// 测试替身未实现显式程序集 CQRS 处理器接入入口。 /// 测试替身未实现显式程序集 CQRS 处理器接入入口。
/// </summary> /// </summary>
/// <param name="assemblies">要接入的程序集集合。</param> /// <param name="assemblies">要接入的程序集集合。</param>
/// <exception cref="NotImplementedException">该测试替身不参与 CQRS 程序集接入路径验证。</exception> /// <exception cref="NotSupportedException">该测试替身不参与 CQRS 程序集接入路径验证。</exception>
public void RegisterCqrsHandlersFromAssemblies(IEnumerable<Assembly> assemblies) public void RegisterCqrsHandlersFromAssemblies(IEnumerable<Assembly> assemblies)
{ {
throw new NotImplementedException(); throw new NotSupportedException();
} }
public IArchitectureModule InstallModule(IArchitectureModule module) public IArchitectureModule InstallModule(IArchitectureModule module)
{ {
throw new NotImplementedException(); throw new NotSupportedException();
} }
IArchitectureLifecycleHook IArchitecture.RegisterLifecycleHook(IArchitectureLifecycleHook hook) IArchitectureLifecycleHook IArchitecture.RegisterLifecycleHook(IArchitectureLifecycleHook hook)
{ {
throw new NotImplementedException(); throw new NotSupportedException();
} }
Task IArchitecture.WaitUntilReadyAsync() Task IArchitecture.WaitUntilReadyAsync()
@ -223,17 +223,17 @@ public class TestArchitectureWithRegistry : IArchitecture
public void RegisterUtility<T>(Action<T>? onCreated = default(Action<T>?)) where T : class, IUtility public void RegisterUtility<T>(Action<T>? onCreated = default(Action<T>?)) where T : class, IUtility
{ {
throw new NotImplementedException(); throw new NotSupportedException();
} }
public void RegisterModel<T>(Action<T>? onCreated = default(Action<T>?)) where T : class, IModel public void RegisterModel<T>(Action<T>? onCreated = default(Action<T>?)) where T : class, IModel
{ {
throw new NotImplementedException(); throw new NotSupportedException();
} }
public void RegisterSystem<T>(Action<T>? onCreated = default(Action<T>?)) where T : class, ISystem public void RegisterSystem<T>(Action<T>? onCreated = default(Action<T>?)) where T : class, ISystem
{ {
throw new NotImplementedException(); throw new NotSupportedException();
} }
public void Initialize() public void Initialize()
@ -242,7 +242,7 @@ public class TestArchitectureWithRegistry : IArchitecture
public void Destroy() public void Destroy()
{ {
throw new NotImplementedException(); throw new NotSupportedException();
} }
Task IAsyncInitializable.InitializeAsync() Task IAsyncInitializable.InitializeAsync()
@ -257,7 +257,7 @@ public class TestArchitectureWithRegistry : IArchitecture
public Task WaitUntilReadyAsync() public Task WaitUntilReadyAsync()
{ {
throw new NotImplementedException(); throw new NotSupportedException();
} }
public void RegisterLifecycleHook(IArchitectureLifecycleHook hook) public void RegisterLifecycleHook(IArchitectureLifecycleHook hook)
@ -266,12 +266,12 @@ public class TestArchitectureWithRegistry : IArchitecture
public Task InitializeAsync() public Task InitializeAsync()
{ {
throw new NotImplementedException(); throw new NotSupportedException();
} }
public ValueTask DestroyAsync() public ValueTask DestroyAsync()
{ {
throw new NotImplementedException(); throw new NotSupportedException();
} }
} }
@ -313,72 +313,72 @@ public class TestArchitectureWithoutRegistry : IArchitecture
T IArchitecture.RegisterSystem<T>(T system) T IArchitecture.RegisterSystem<T>(T system)
{ {
throw new NotImplementedException(); throw new NotSupportedException();
} }
T IArchitecture.RegisterModel<T>(T model) T IArchitecture.RegisterModel<T>(T model)
{ {
throw new NotImplementedException(); throw new NotSupportedException();
} }
T IArchitecture.RegisterUtility<T>(T utility) T IArchitecture.RegisterUtility<T>(T utility)
{ {
throw new NotImplementedException(); throw new NotSupportedException();
} }
public void RegisterCqrsPipelineBehavior<TBehavior>() where TBehavior : class public void RegisterCqrsPipelineBehavior<TBehavior>() where TBehavior : class
{ {
throw new NotImplementedException(); throw new NotSupportedException();
} }
/// <summary> /// <summary>
/// 测试替身未实现显式程序集 CQRS 处理器接入入口。 /// 测试替身未实现显式程序集 CQRS 处理器接入入口。
/// </summary> /// </summary>
/// <param name="assembly">包含 CQRS 处理器或生成注册器的程序集。</param> /// <param name="assembly">包含 CQRS 处理器或生成注册器的程序集。</param>
/// <exception cref="NotImplementedException">该测试替身不参与 CQRS 程序集接入路径验证。</exception> /// <exception cref="NotSupportedException">该测试替身不参与 CQRS 程序集接入路径验证。</exception>
public void RegisterCqrsHandlersFromAssembly(Assembly assembly) public void RegisterCqrsHandlersFromAssembly(Assembly assembly)
{ {
throw new NotImplementedException(); throw new NotSupportedException();
} }
/// <summary> /// <summary>
/// 测试替身未实现显式程序集 CQRS 处理器接入入口。 /// 测试替身未实现显式程序集 CQRS 处理器接入入口。
/// </summary> /// </summary>
/// <param name="assemblies">要接入的程序集集合。</param> /// <param name="assemblies">要接入的程序集集合。</param>
/// <exception cref="NotImplementedException">该测试替身不参与 CQRS 程序集接入路径验证。</exception> /// <exception cref="NotSupportedException">该测试替身不参与 CQRS 程序集接入路径验证。</exception>
public void RegisterCqrsHandlersFromAssemblies(IEnumerable<Assembly> assemblies) public void RegisterCqrsHandlersFromAssemblies(IEnumerable<Assembly> assemblies)
{ {
throw new NotImplementedException(); throw new NotSupportedException();
} }
public IArchitectureModule InstallModule(IArchitectureModule module) public IArchitectureModule InstallModule(IArchitectureModule module)
{ {
throw new NotImplementedException(); throw new NotSupportedException();
} }
IArchitectureLifecycleHook IArchitecture.RegisterLifecycleHook(IArchitectureLifecycleHook hook) IArchitectureLifecycleHook IArchitecture.RegisterLifecycleHook(IArchitectureLifecycleHook hook)
{ {
throw new NotImplementedException(); throw new NotSupportedException();
} }
public Task WaitUntilReadyAsync() public Task WaitUntilReadyAsync()
{ {
throw new NotImplementedException(); throw new NotSupportedException();
} }
public void RegisterUtility<T>(Action<T>? onCreated = default(Action<T>?)) where T : class, IUtility public void RegisterUtility<T>(Action<T>? onCreated = default(Action<T>?)) where T : class, IUtility
{ {
throw new NotImplementedException(); throw new NotSupportedException();
} }
public void RegisterModel<T>(Action<T>? onCreated = default(Action<T>?)) where T : class, IModel public void RegisterModel<T>(Action<T>? onCreated = default(Action<T>?)) where T : class, IModel
{ {
throw new NotImplementedException(); throw new NotSupportedException();
} }
public void RegisterSystem<T>(Action<T>? onCreated = default(Action<T>?)) where T : class, ISystem public void RegisterSystem<T>(Action<T>? onCreated = default(Action<T>?)) where T : class, ISystem
{ {
throw new NotImplementedException(); throw new NotSupportedException();
} }
public void Initialize() public void Initialize()
@ -387,17 +387,17 @@ public class TestArchitectureWithoutRegistry : IArchitecture
public Task InitializeAsync() public Task InitializeAsync()
{ {
throw new NotImplementedException(); throw new NotSupportedException();
} }
public ValueTask DestroyAsync() public ValueTask DestroyAsync()
{ {
throw new NotImplementedException(); throw new NotSupportedException();
} }
public void Destroy() public void Destroy()
{ {
throw new NotImplementedException(); throw new NotSupportedException();
} }
public void RegisterLifecycleHook(IArchitectureLifecycleHook hook) public void RegisterLifecycleHook(IArchitectureLifecycleHook hook)

View File

@ -6,6 +6,7 @@ using GFramework.Core.Abstractions.Rule;
using GFramework.Core.Coroutine.Extensions; using GFramework.Core.Coroutine.Extensions;
using GFramework.Core.Coroutine.Instructions; using GFramework.Core.Coroutine.Instructions;
using Moq; using Moq;
using NUnit.Framework;
namespace GFramework.Core.Tests.Coroutine; namespace GFramework.Core.Tests.Coroutine;
@ -18,6 +19,8 @@ namespace GFramework.Core.Tests.Coroutine;
[TestFixture] [TestFixture]
public class CommandCoroutineExtensionsTests public class CommandCoroutineExtensionsTests
{ {
private static readonly TimeSpan WaitForTaskTimeout = TimeSpan.FromSeconds(1);
/// <summary> /// <summary>
/// 测试用的简单命令类 /// 测试用的简单命令类
/// </summary> /// </summary>
@ -83,15 +86,10 @@ public class CommandCoroutineExtensionsTests
var coroutine = contextAware.SendCommandCoroutineWithErrorHandler(command, ex => capturedException = ex); var coroutine = contextAware.SendCommandCoroutineWithErrorHandler(command, ex => capturedException = ex);
// 迭代协程直到完成 Assert.That(coroutine.MoveNext(), Is.True);
while (coroutine.MoveNext()) Assert.That(coroutine.Current, Is.TypeOf<WaitForTask>());
{ await WaitForTaskAsync((WaitForTask)coroutine.Current);
if (coroutine.Current is WaitForTask waitForTask) Assert.That(coroutine.MoveNext(), Is.False);
{
// 等待任务完成
await Task.Delay(10);
}
}
Assert.That(capturedException, Is.Null); Assert.That(capturedException, Is.Null);
} }
@ -114,15 +112,10 @@ public class CommandCoroutineExtensionsTests
var coroutine = contextAware.SendCommandCoroutineWithErrorHandler(command, ex => capturedException = ex); var coroutine = contextAware.SendCommandCoroutineWithErrorHandler(command, ex => capturedException = ex);
// 迭代协程直到完成 Assert.That(coroutine.MoveNext(), Is.True);
while (coroutine.MoveNext()) Assert.That(coroutine.Current, Is.TypeOf<WaitForTask>());
{ await WaitForTaskAsync((WaitForTask)coroutine.Current);
if (coroutine.Current is WaitForTask waitForTask) Assert.That(coroutine.MoveNext(), Is.False);
{
// 等待任务完成
await Task.Delay(10);
}
}
Assert.That(capturedException, Is.Not.Null); Assert.That(capturedException, Is.Not.Null);
// 异常被包装为 AggregateException // 异常被包装为 AggregateException
@ -148,17 +141,12 @@ public class CommandCoroutineExtensionsTests
var coroutine = contextAware.SendCommandCoroutineWithErrorHandler(command); var coroutine = contextAware.SendCommandCoroutineWithErrorHandler(command);
// 迭代协程应该抛出异常 Assert.That(coroutine.MoveNext(), Is.True);
Assert.Throws<InvalidOperationException>(() => Assert.That(coroutine.Current, Is.TypeOf<WaitForTask>());
{ Assert.That(
while (coroutine.MoveNext()) SpinWait.SpinUntil(() => ((WaitForTask)coroutine.Current).IsDone, WaitForTaskTimeout),
{ Is.True);
if (coroutine.Current is WaitForTask waitForTask) Assert.Throws<InvalidOperationException>(() => coroutine.MoveNext());
{
Task.Delay(10).Wait();
}
}
});
} }
/// <summary> /// <summary>
@ -201,8 +189,9 @@ public class CommandCoroutineExtensionsTests
}); });
// 启动协程并等待命令执行完成 // 启动协程并等待命令执行完成
coroutine.MoveNext(); // 进入命令发送阶段 Assert.That(coroutine.MoveNext(), Is.True); // 进入命令发送阶段
if (coroutine.Current is WaitForTask waitForTask) await Task.Delay(10); // 等待命令任务完成 Assert.That(coroutine.Current, Is.TypeOf<WaitForTask>());
await WaitForTaskAsync((WaitForTask)coroutine.Current);
// 此时协程应该在等待事件 // 此时协程应该在等待事件
Assert.That(coroutine.MoveNext(), Is.True); // 等待事件阶段 Assert.That(coroutine.MoveNext(), Is.True); // 等待事件阶段
@ -296,15 +285,16 @@ public class CommandCoroutineExtensionsTests
command); // null回调 command); // null回调
// 启动协程 // 启动协程
coroutine.MoveNext(); // 进入命令发送阶段 Assert.That(coroutine.MoveNext(), Is.True); // 进入命令发送阶段
if (coroutine.Current is WaitForTask waitForTask) await Task.Delay(10); // 等待命令任务完成 Assert.That(coroutine.Current, Is.TypeOf<WaitForTask>());
await WaitForTaskAsync((WaitForTask)coroutine.Current);
// 触发事件 // 触发事件
var testEvent = new TestEvent { Data = "TestData" }; var testEvent = new TestEvent { Data = "TestData" };
eventCallback?.Invoke(testEvent); eventCallback?.Invoke(testEvent);
// 协程应该能正常完成 // 协程应该能正常完成
Assert.That(() => coroutine.MoveNext(), Throws.Nothing); Assert.DoesNotThrow(() => coroutine.MoveNext());
} }
/// <summary> /// <summary>
@ -340,8 +330,9 @@ public class CommandCoroutineExtensionsTests
_ => { }); _ => { });
// 启动协程 - 命令失败时协程仍然继续 // 启动协程 - 命令失败时协程仍然继续
coroutine.MoveNext(); // 进入命令发送阶段 Assert.That(coroutine.MoveNext(), Is.True); // 进入命令发送阶段
if (coroutine.Current is WaitForTask waitForTask) await Task.Delay(10); // 等待命令任务完成 Assert.That(coroutine.Current, Is.TypeOf<WaitForTask>());
await WaitForTaskAsync((WaitForTask)coroutine.Current);
// 命令执行失败后,协程继续执行 // 命令执行失败后,协程继续执行
Assert.Pass(); Assert.Pass();
@ -441,4 +432,18 @@ public class CommandCoroutineExtensionsTests
// 调用 MoveNext 时应该抛出 InvalidOperationException // 调用 MoveNext 时应该抛出 InvalidOperationException
Assert.Throws<InvalidOperationException>(() => coroutine.MoveNext()); Assert.Throws<InvalidOperationException>(() => coroutine.MoveNext());
} }
private static async Task WaitForTaskAsync(WaitForTask waitForTask)
{
var timeoutAt = DateTime.UtcNow + WaitForTaskTimeout;
// 协程通过轮询 IsDone 观察异步命令完成,这里保持相同语义但避免固定延时。
while (!waitForTask.IsDone)
{
if (DateTime.UtcNow >= timeoutAt)
Assert.Fail("WaitForTask did not complete within the expected time.");
await Task.Yield();
}
}
} }

View File

@ -66,7 +66,7 @@ public class TaskCoroutineExtensionsTests
var task = Task.FromResult(42); var task = Task.FromResult(42);
var instruction = task.AsCoroutineInstruction(); var instruction = task.AsCoroutineInstruction();
task.Wait(); task.ConfigureAwait(false).GetAwaiter().GetResult();
Assert.That(instruction.Result, Is.EqualTo(42)); Assert.That(instruction.Result, Is.EqualTo(42));
} }
@ -165,7 +165,7 @@ public class TaskCoroutineExtensionsTests
Assert.That(completed, Is.False); Assert.That(completed, Is.False);
tcs.SetResult(null); tcs.SetResult(null);
Task.Delay(50).Wait(); Task.Delay(50).ConfigureAwait(false).GetAwaiter().GetResult();
scheduler.Update(); scheduler.Update();
scheduler.Update(); scheduler.Update();
@ -189,7 +189,7 @@ public class TaskCoroutineExtensionsTests
Assert.That(scheduler.ActiveCoroutineCount, Is.EqualTo(1)); Assert.That(scheduler.ActiveCoroutineCount, Is.EqualTo(1));
tcs.SetResult(42); tcs.SetResult(42);
Task.Delay(50).Wait(); Task.Delay(50).ConfigureAwait(false).GetAwaiter().GetResult();
scheduler.Update(); scheduler.Update();
scheduler.Update(); scheduler.Update();
@ -265,7 +265,7 @@ public class TaskCoroutineExtensionsTests
tcs.SetResult(null); tcs.SetResult(null);
tcs2.SetResult(42); tcs2.SetResult(42);
Task.Delay(50).Wait(); Task.Delay(50).ConfigureAwait(false).GetAwaiter().GetResult();
scheduler.Update(); scheduler.Update();
scheduler.Update(); scheduler.Update();

View File

@ -14,7 +14,7 @@ namespace GFramework.Core.Tests.Coroutine
} }
[Test] [Test]
public async Task Constructor_WithCompletedTask_IsDoneImmediately() public void Constructor_WithCompletedTask_IsDoneImmediately()
{ {
// Arrange // Arrange
var completedTask = Task.FromResult("test"); var completedTask = Task.FromResult("test");
@ -28,7 +28,7 @@ namespace GFramework.Core.Tests.Coroutine
} }
[Test] [Test]
public async Task Constructor_WithIncompleteTask_IsNotDoneInitially() public void Constructor_WithIncompleteTask_IsNotDoneInitially()
{ {
// Arrange // Arrange
var tcs = new TaskCompletionSource<string>(); var tcs = new TaskCompletionSource<string>();
@ -54,7 +54,7 @@ namespace GFramework.Core.Tests.Coroutine
// Act // Act
tcs.SetResult("completed"); tcs.SetResult("completed");
await Task.Delay(10); // Allow time for continuation await Task.Delay(10).ConfigureAwait(false); // Allow time for continuation
// Assert final state // Assert final state
Assert.That(waitForTask.IsDone, Is.True); Assert.That(waitForTask.IsDone, Is.True);
@ -62,7 +62,7 @@ namespace GFramework.Core.Tests.Coroutine
} }
[Test] [Test]
public async Task Update_DoesNotChangeState() public void Update_DoesNotChangeState()
{ {
// Arrange // Arrange
var completedTask = Task.FromResult("test"); var completedTask = Task.FromResult("test");
@ -85,7 +85,7 @@ namespace GFramework.Core.Tests.Coroutine
// Act // Act
tcs.SetException(new InvalidOperationException("Test exception")); tcs.SetException(new InvalidOperationException("Test exception"));
await Task.Delay(10); // Allow time for continuation await Task.Delay(10).ConfigureAwait(false); // Allow time for continuation
// Assert // Assert
Assert.That(waitForTask.IsDone, Is.True); Assert.That(waitForTask.IsDone, Is.True);

View File

@ -33,11 +33,11 @@ public class AsyncExtensionsTests
public void WithTimeout_Should_Throw_TimeoutException_When_Task_Exceeds_Timeout() public void WithTimeout_Should_Throw_TimeoutException_When_Task_Exceeds_Timeout()
{ {
// Act & Assert // Act & Assert
Assert.ThrowsAsync<TimeoutException>(async () => Assert.ThrowsAsync<TimeoutException>(() =>
await AsyncExtensions.WithTimeoutAsync( AsyncExtensions.WithTimeoutAsync(
async ct => async ct =>
{ {
await Task.Delay(TimeSpan.FromSeconds(2), ct); await Task.Delay(TimeSpan.FromSeconds(2), ct).ConfigureAwait(false);
return 42; return 42;
}, },
TimeSpan.FromMilliseconds(100))); TimeSpan.FromMilliseconds(100)));
@ -53,11 +53,11 @@ public class AsyncExtensionsTests
using var cts = new CancellationTokenSource(); using var cts = new CancellationTokenSource();
cts.Cancel(); cts.Cancel();
// Act & Assert // Act & Assert
Assert.ThrowsAsync<TaskCanceledException>(async () => Assert.ThrowsAsync<TaskCanceledException>(() =>
await AsyncExtensions.WithTimeoutAsync( AsyncExtensions.WithTimeoutAsync(
async ct => async ct =>
{ {
await Task.Delay(TimeSpan.FromSeconds(2), ct); await Task.Delay(TimeSpan.FromSeconds(2), ct).ConfigureAwait(false);
return 42; return 42;
}, },
TimeSpan.FromSeconds(1), TimeSpan.FromSeconds(1),
@ -74,13 +74,13 @@ public class AsyncExtensionsTests
var innerTaskCanceled = false; var innerTaskCanceled = false;
// Act & Assert // Act & Assert
Assert.ThrowsAsync<TimeoutException>(async () => Assert.ThrowsAsync<TimeoutException>(() =>
await AsyncExtensions.WithTimeoutAsync( AsyncExtensions.WithTimeoutAsync(
async ct => async ct =>
{ {
try try
{ {
await Task.Delay(TimeSpan.FromSeconds(5), ct); await Task.Delay(TimeSpan.FromSeconds(5), ct).ConfigureAwait(false);
return 0; return 0;
} }
catch (OperationCanceledException) catch (OperationCanceledException)
@ -121,9 +121,9 @@ public class AsyncExtensionsTests
public void WithTimeout_NoResult_Should_Throw_TimeoutException_When_Task_Exceeds_Timeout() public void WithTimeout_NoResult_Should_Throw_TimeoutException_When_Task_Exceeds_Timeout()
{ {
// Act & Assert // Act & Assert
Assert.ThrowsAsync<TimeoutException>(async () => Assert.ThrowsAsync<TimeoutException>(() =>
await AsyncExtensions.WithTimeoutAsync( AsyncExtensions.WithTimeoutAsync(
ct => Task.Delay(TimeSpan.FromSeconds(2), ct), ct => Task.Delay(TimeSpan.FromSeconds(2), ct).ConfigureAwait(false),
TimeSpan.FromMilliseconds(100))); TimeSpan.FromMilliseconds(100)));
} }
@ -137,13 +137,13 @@ public class AsyncExtensionsTests
var innerTaskCanceled = false; var innerTaskCanceled = false;
// Act & Assert // Act & Assert
Assert.ThrowsAsync<TimeoutException>(async () => Assert.ThrowsAsync<TimeoutException>(() =>
await AsyncExtensions.WithTimeoutAsync( AsyncExtensions.WithTimeoutAsync(
async ct => async ct =>
{ {
try try
{ {
await Task.Delay(TimeSpan.FromSeconds(5), ct); await Task.Delay(TimeSpan.FromSeconds(5), ct).ConfigureAwait(false);
} }
catch (OperationCanceledException) catch (OperationCanceledException)
{ {
@ -217,8 +217,8 @@ public class AsyncExtensionsTests
}; };
// Act & Assert // Act & Assert
Assert.ThrowsAsync<AggregateException>(async () => Assert.ThrowsAsync<AggregateException>(() =>
await taskFactory.WithRetryAsync(2, TimeSpan.FromMilliseconds(10))); taskFactory.WithRetryAsync(2, TimeSpan.FromMilliseconds(10)));
} }
/// <summary> /// <summary>

View File

@ -414,9 +414,9 @@ public class ResultTTests
var result = Result<int>.Succeed(42); var result = Result<int>.Succeed(42);
var mapped = await result.MapAsync(async x => var mapped = await result.MapAsync(async x =>
{ {
await Task.Delay(1); await Task.Delay(1).ConfigureAwait(false);
return x.ToString(CultureInfo.InvariantCulture); return x.ToString(CultureInfo.InvariantCulture);
}); }).ConfigureAwait(false);
Assert.That(mapped.IsSuccess, Is.True); Assert.That(mapped.IsSuccess, Is.True);
Assert.That(mapped.Match(succ: v => v, fail: _ => ""), Is.EqualTo("42")); Assert.That(mapped.Match(succ: v => v, fail: _ => ""), Is.EqualTo("42"));
} }
@ -431,9 +431,9 @@ public class ResultTTests
var result = Result<int>.Fail(exception); var result = Result<int>.Fail(exception);
var mapped = await result.MapAsync(async x => var mapped = await result.MapAsync(async x =>
{ {
await Task.Delay(1); await Task.Delay(1).ConfigureAwait(false);
return x.ToString(CultureInfo.InvariantCulture); return x.ToString(CultureInfo.InvariantCulture);
}); }).ConfigureAwait(false);
Assert.That(mapped.IsFaulted, Is.True); Assert.That(mapped.IsFaulted, Is.True);
Assert.That(mapped.Exception, Is.SameAs(exception)); Assert.That(mapped.Exception, Is.SameAs(exception));
} }
@ -447,9 +447,9 @@ public class ResultTTests
var result = Result<int>.Succeed(42); var result = Result<int>.Succeed(42);
var mapped = await result.MapAsync<string>(async _ => var mapped = await result.MapAsync<string>(async _ =>
{ {
await Task.Delay(1); await Task.Delay(1).ConfigureAwait(false);
throw new InvalidOperationException("Async error"); throw new InvalidOperationException("Async error");
}); }).ConfigureAwait(false);
Assert.That(mapped.IsFaulted, Is.True); Assert.That(mapped.IsFaulted, Is.True);
Assert.That(mapped.Exception, Is.TypeOf<InvalidOperationException>()); Assert.That(mapped.Exception, Is.TypeOf<InvalidOperationException>());
} }
@ -551,7 +551,7 @@ public class ResultTTests
public void Equals_Should_Return_False_When_Exception_Types_Differ() public void Equals_Should_Return_False_When_Exception_Types_Differ()
{ {
var result1 = Result<int>.Fail(new InvalidOperationException("Error")); var result1 = Result<int>.Fail(new InvalidOperationException("Error"));
var result2 = Result<int>.Fail(new ArgumentException("Error")); var result2 = Result<int>.Fail(new InvalidCastException("Error"));
Assert.That(result1.Equals(result2), Is.False); Assert.That(result1.Equals(result2), Is.False);
} }

View File

@ -152,22 +152,22 @@ public class LogContextTests
var task1Values = new List<object?>(); var task1Values = new List<object?>();
var task2Values = new List<object?>(); var task2Values = new List<object?>();
var task1 = Task.Run(() => var task1 = Task.Run(async () =>
{ {
using (LogContext.Push("TaskId", "Task1")) using (LogContext.Push("TaskId", "Task1"))
{ {
task1Values.Add(LogContext.Current["TaskId"]); task1Values.Add(LogContext.Current["TaskId"]);
Task.Delay(50).Wait(); await Task.Delay(50);
task1Values.Add(LogContext.Current["TaskId"]); task1Values.Add(LogContext.Current["TaskId"]);
} }
}); });
var task2 = Task.Run(() => var task2 = Task.Run(async () =>
{ {
using (LogContext.Push("TaskId", "Task2")) using (LogContext.Push("TaskId", "Task2"))
{ {
task2Values.Add(LogContext.Current["TaskId"]); task2Values.Add(LogContext.Current["TaskId"]);
Task.Delay(50).Wait(); await Task.Delay(50);
task2Values.Add(LogContext.Current["TaskId"]); task2Values.Add(LogContext.Current["TaskId"]);
} }
}); });

View File

@ -22,9 +22,9 @@ public class PauseStackManagerTests
/// 在每个测试方法执行后清理资源 /// 在每个测试方法执行后清理资源
/// </summary> /// </summary>
[TearDown] [TearDown]
public void TearDown() public async Task TearDown()
{ {
_manager.DestroyAsync(); await _manager.DestroyAsync().ConfigureAwait(false);
} }
private PauseStackManager _manager = null!; private PauseStackManager _manager = null!;
@ -416,7 +416,7 @@ public class PauseStackManagerTests
_manager.Push("Gameplay", PauseGroup.Gameplay); _manager.Push("Gameplay", PauseGroup.Gameplay);
mockHandler.Reset(); mockHandler.Reset();
await _manager.DestroyAsync(); await _manager.DestroyAsync().ConfigureAwait(false);
Assert.That(mockHandler.CallCount, Is.EqualTo(2)); Assert.That(mockHandler.CallCount, Is.EqualTo(2));
Assert.That(mockHandler.LastIsPaused, Is.False); Assert.That(mockHandler.LastIsPaused, Is.False);

View File

@ -28,7 +28,10 @@ public static class AsyncExtensions
TimeSpan timeout, TimeSpan timeout,
CancellationToken cancellationToken = default) CancellationToken cancellationToken = default)
{ {
ArgumentNullException.ThrowIfNull(taskFactory); if (taskFactory is null)
{
throw new ArgumentNullException(nameof(taskFactory));
}
// linkedCts 同时响应:超时 + 外部取消 // linkedCts 同时响应:超时 + 外部取消
using var linkedCts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken); using var linkedCts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken);
@ -71,7 +74,10 @@ public static class AsyncExtensions
TimeSpan timeout, TimeSpan timeout,
CancellationToken cancellationToken = default) CancellationToken cancellationToken = default)
{ {
ArgumentNullException.ThrowIfNull(taskFactory); if (taskFactory is null)
{
throw new ArgumentNullException(nameof(taskFactory));
}
using var linkedCts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken); using var linkedCts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken);
linkedCts.CancelAfter(timeout); linkedCts.CancelAfter(timeout);
@ -113,8 +119,15 @@ public static class AsyncExtensions
/// </example> /// </example>
public static async Task<T> WithFallbackAsync<T>(this Task<T> task, Func<Exception, T> fallback) public static async Task<T> WithFallbackAsync<T>(this Task<T> task, Func<Exception, T> fallback)
{ {
ArgumentNullException.ThrowIfNull(task); if (task is null)
ArgumentNullException.ThrowIfNull(fallback); {
throw new ArgumentNullException(nameof(task));
}
if (fallback is null)
{
throw new ArgumentNullException(nameof(fallback));
}
try try
{ {

View File

@ -20,8 +20,15 @@ public static class CollectionExtensions
/// </example> /// </example>
public static void ForEach<T>(this IEnumerable<T> source, Action<T> action) public static void ForEach<T>(this IEnumerable<T> source, Action<T> action)
{ {
ArgumentNullException.ThrowIfNull(source); if (source is null)
ArgumentNullException.ThrowIfNull(action); {
throw new ArgumentNullException(nameof(source));
}
if (action is null)
{
throw new ArgumentNullException(nameof(action));
}
foreach (var item in source) action(item); foreach (var item in source) action(item);
} }
@ -58,7 +65,10 @@ public static class CollectionExtensions
/// </example> /// </example>
public static IEnumerable<T> WhereNotNull<T>(this IEnumerable<T?> source) where T : class public static IEnumerable<T> WhereNotNull<T>(this IEnumerable<T?> source) where T : class
{ {
ArgumentNullException.ThrowIfNull(source); if (source is null)
{
throw new ArgumentNullException(nameof(source));
}
return source.Where(item => item is not null)!; return source.Where(item => item is not null)!;
} }
@ -88,9 +98,20 @@ public static class CollectionExtensions
Func<T, TValue> valueSelector) where TKey : notnull Func<T, TValue> valueSelector) where TKey : notnull
#pragma warning restore MA0016 #pragma warning restore MA0016
{ {
ArgumentNullException.ThrowIfNull(source); if (source is null)
ArgumentNullException.ThrowIfNull(keySelector); {
ArgumentNullException.ThrowIfNull(valueSelector); throw new ArgumentNullException(nameof(source));
}
if (keySelector is null)
{
throw new ArgumentNullException(nameof(keySelector));
}
if (valueSelector is null)
{
throw new ArgumentNullException(nameof(valueSelector));
}
var dictionary = new Dictionary<TKey, TValue>(); var dictionary = new Dictionary<TKey, TValue>();

View File

@ -19,8 +19,15 @@ public static class ContextAwareCommandExtensions
public static TResult SendCommand<TResult>(this IContextAware contextAware, public static TResult SendCommand<TResult>(this IContextAware contextAware,
ICommand<TResult> command) ICommand<TResult> command)
{ {
ArgumentNullException.ThrowIfNull(contextAware); if (contextAware is null)
ArgumentNullException.ThrowIfNull(command); {
throw new ArgumentNullException(nameof(contextAware));
}
if (command is null)
{
throw new ArgumentNullException(nameof(command));
}
var context = contextAware.GetContext(); var context = contextAware.GetContext();
return context.SendCommand(command); return context.SendCommand(command);
@ -34,8 +41,15 @@ public static class ContextAwareCommandExtensions
/// <exception cref="ArgumentNullException">当 contextAware 或 command 为 null 时抛出</exception> /// <exception cref="ArgumentNullException">当 contextAware 或 command 为 null 时抛出</exception>
public static void SendCommand(this IContextAware contextAware, ICommand command) public static void SendCommand(this IContextAware contextAware, ICommand command)
{ {
ArgumentNullException.ThrowIfNull(contextAware); if (contextAware is null)
ArgumentNullException.ThrowIfNull(command); {
throw new ArgumentNullException(nameof(contextAware));
}
if (command is null)
{
throw new ArgumentNullException(nameof(command));
}
var context = contextAware.GetContext(); var context = contextAware.GetContext();
context.SendCommand(command); context.SendCommand(command);
@ -50,8 +64,15 @@ public static class ContextAwareCommandExtensions
/// <exception cref="ArgumentNullException">当 contextAware 或 command 为 null 时抛出</exception> /// <exception cref="ArgumentNullException">当 contextAware 或 command 为 null 时抛出</exception>
public static async Task SendCommandAsync(this IContextAware contextAware, IAsyncCommand command) public static async Task SendCommandAsync(this IContextAware contextAware, IAsyncCommand command)
{ {
ArgumentNullException.ThrowIfNull(contextAware); if (contextAware is null)
ArgumentNullException.ThrowIfNull(command); {
throw new ArgumentNullException(nameof(contextAware));
}
if (command is null)
{
throw new ArgumentNullException(nameof(command));
}
var context = contextAware.GetContext(); var context = contextAware.GetContext();
await context.SendCommandAsync(command).ConfigureAwait(false); await context.SendCommandAsync(command).ConfigureAwait(false);
@ -68,8 +89,15 @@ public static class ContextAwareCommandExtensions
public static async Task<TResult> SendCommandAsync<TResult>(this IContextAware contextAware, public static async Task<TResult> SendCommandAsync<TResult>(this IContextAware contextAware,
IAsyncCommand<TResult> command) IAsyncCommand<TResult> command)
{ {
ArgumentNullException.ThrowIfNull(contextAware); if (contextAware is null)
ArgumentNullException.ThrowIfNull(command); {
throw new ArgumentNullException(nameof(contextAware));
}
if (command is null)
{
throw new ArgumentNullException(nameof(command));
}
var context = contextAware.GetContext(); var context = contextAware.GetContext();
return await context.SendCommandAsync(command).ConfigureAwait(false); return await context.SendCommandAsync(command).ConfigureAwait(false);

View File

@ -16,7 +16,11 @@ public static class ContextAwareEnvironmentExtensions
/// <returns>指定类型的环境对象,如果无法转换则返回null</returns> /// <returns>指定类型的环境对象,如果无法转换则返回null</returns>
public static T? GetEnvironment<T>(this IContextAware contextAware) where T : class public static T? GetEnvironment<T>(this IContextAware contextAware) where T : class
{ {
ArgumentNullException.ThrowIfNull(contextAware); if (contextAware is null)
{
throw new ArgumentNullException(nameof(contextAware));
}
var context = contextAware.GetContext(); var context = contextAware.GetContext();
return context.GetEnvironment() as T; return context.GetEnvironment() as T;
} }
@ -28,7 +32,11 @@ public static class ContextAwareEnvironmentExtensions
/// <returns>环境对象</returns> /// <returns>环境对象</returns>
public static IEnvironment GetEnvironment(this IContextAware contextAware) public static IEnvironment GetEnvironment(this IContextAware contextAware)
{ {
ArgumentNullException.ThrowIfNull(contextAware); if (contextAware is null)
{
throw new ArgumentNullException(nameof(contextAware));
}
var context = contextAware.GetContext(); var context = contextAware.GetContext();
return context.GetEnvironment(); return context.GetEnvironment();
} }

View File

@ -16,7 +16,11 @@ public static class ContextAwareEventExtensions
/// <exception cref="ArgumentNullException">当 contextAware 为 null 时抛出</exception> /// <exception cref="ArgumentNullException">当 contextAware 为 null 时抛出</exception>
public static void SendEvent<TEvent>(this IContextAware contextAware) where TEvent : new() public static void SendEvent<TEvent>(this IContextAware contextAware) where TEvent : new()
{ {
ArgumentNullException.ThrowIfNull(contextAware); if (contextAware is null)
{
throw new ArgumentNullException(nameof(contextAware));
}
var context = contextAware.GetContext(); var context = contextAware.GetContext();
context.SendEvent<TEvent>(); context.SendEvent<TEvent>();
} }
@ -30,8 +34,15 @@ public static class ContextAwareEventExtensions
/// <exception cref="ArgumentNullException">当 contextAware 或 e 为 null 时抛出</exception> /// <exception cref="ArgumentNullException">当 contextAware 或 e 为 null 时抛出</exception>
public static void SendEvent<TEvent>(this IContextAware contextAware, TEvent e) where TEvent : class public static void SendEvent<TEvent>(this IContextAware contextAware, TEvent e) where TEvent : class
{ {
ArgumentNullException.ThrowIfNull(contextAware); if (contextAware is null)
ArgumentNullException.ThrowIfNull(e); {
throw new ArgumentNullException(nameof(contextAware));
}
if (e is null)
{
throw new ArgumentNullException(nameof(e));
}
var context = contextAware.GetContext(); var context = contextAware.GetContext();
context.SendEvent(e); context.SendEvent(e);
@ -46,8 +57,15 @@ public static class ContextAwareEventExtensions
/// <returns>事件注销接口</returns> /// <returns>事件注销接口</returns>
public static IUnRegister RegisterEvent<TEvent>(this IContextAware contextAware, Action<TEvent> handler) public static IUnRegister RegisterEvent<TEvent>(this IContextAware contextAware, Action<TEvent> handler)
{ {
ArgumentNullException.ThrowIfNull(contextAware); if (contextAware is null)
ArgumentNullException.ThrowIfNull(handler); {
throw new ArgumentNullException(nameof(contextAware));
}
if (handler is null)
{
throw new ArgumentNullException(nameof(handler));
}
var context = contextAware.GetContext(); var context = contextAware.GetContext();
return context.RegisterEvent(handler); return context.RegisterEvent(handler);
@ -61,8 +79,15 @@ public static class ContextAwareEventExtensions
/// <param name="onEvent">之前绑定的事件处理器</param> /// <param name="onEvent">之前绑定的事件处理器</param>
public static void UnRegisterEvent<TEvent>(this IContextAware contextAware, Action<TEvent> onEvent) public static void UnRegisterEvent<TEvent>(this IContextAware contextAware, Action<TEvent> onEvent)
{ {
ArgumentNullException.ThrowIfNull(contextAware); if (contextAware is null)
ArgumentNullException.ThrowIfNull(onEvent); {
throw new ArgumentNullException(nameof(contextAware));
}
if (onEvent is null)
{
throw new ArgumentNullException(nameof(onEvent));
}
var context = contextAware.GetContext(); var context = contextAware.GetContext();
context.UnRegisterEvent(onEvent); context.UnRegisterEvent(onEvent);

View File

@ -18,8 +18,15 @@ public static class ContextAwareQueryExtensions
/// <exception cref="ArgumentNullException">当 contextAware 或 query 为 null 时抛出</exception> /// <exception cref="ArgumentNullException">当 contextAware 或 query 为 null 时抛出</exception>
public static TResult SendQuery<TResult>(this IContextAware contextAware, IQuery<TResult> query) public static TResult SendQuery<TResult>(this IContextAware contextAware, IQuery<TResult> query)
{ {
ArgumentNullException.ThrowIfNull(contextAware); if (contextAware is null)
ArgumentNullException.ThrowIfNull(query); {
throw new ArgumentNullException(nameof(contextAware));
}
if (query is null)
{
throw new ArgumentNullException(nameof(query));
}
var context = contextAware.GetContext(); var context = contextAware.GetContext();
return context.SendQuery(query); return context.SendQuery(query);
@ -37,8 +44,15 @@ public static class ContextAwareQueryExtensions
public static async Task<TResult> SendQueryAsync<TResult>(this IContextAware contextAware, public static async Task<TResult> SendQueryAsync<TResult>(this IContextAware contextAware,
IAsyncQuery<TResult> query) IAsyncQuery<TResult> query)
{ {
ArgumentNullException.ThrowIfNull(contextAware); if (contextAware is null)
ArgumentNullException.ThrowIfNull(query); {
throw new ArgumentNullException(nameof(contextAware));
}
if (query is null)
{
throw new ArgumentNullException(nameof(query));
}
var context = contextAware.GetContext(); var context = contextAware.GetContext();
return await context.SendQueryAsync(query).ConfigureAwait(false); return await context.SendQueryAsync(query).ConfigureAwait(false);

View File

@ -24,7 +24,11 @@ public static class ContextAwareServiceExtensions
/// <exception cref="InvalidOperationException">当指定服务未注册时抛出</exception> /// <exception cref="InvalidOperationException">当指定服务未注册时抛出</exception>
public static TService GetService<TService>(this IContextAware contextAware) where TService : class public static TService GetService<TService>(this IContextAware contextAware) where TService : class
{ {
ArgumentNullException.ThrowIfNull(contextAware); if (contextAware is null)
{
throw new ArgumentNullException(nameof(contextAware));
}
var context = contextAware.GetContext(); var context = contextAware.GetContext();
return GetRequiredComponent(context, static architectureContext => architectureContext.GetService<TService>(), return GetRequiredComponent(context, static architectureContext => architectureContext.GetService<TService>(),
"Service"); "Service");
@ -40,7 +44,11 @@ public static class ContextAwareServiceExtensions
/// <exception cref="InvalidOperationException">当指定系统未注册时抛出</exception> /// <exception cref="InvalidOperationException">当指定系统未注册时抛出</exception>
public static TSystem GetSystem<TSystem>(this IContextAware contextAware) where TSystem : class, ISystem public static TSystem GetSystem<TSystem>(this IContextAware contextAware) where TSystem : class, ISystem
{ {
ArgumentNullException.ThrowIfNull(contextAware); if (contextAware is null)
{
throw new ArgumentNullException(nameof(contextAware));
}
var context = contextAware.GetContext(); var context = contextAware.GetContext();
return GetRequiredComponent(context, static architectureContext => architectureContext.GetSystem<TSystem>(), return GetRequiredComponent(context, static architectureContext => architectureContext.GetSystem<TSystem>(),
"System"); "System");
@ -56,7 +64,11 @@ public static class ContextAwareServiceExtensions
/// <exception cref="InvalidOperationException">当指定模型未注册时抛出</exception> /// <exception cref="InvalidOperationException">当指定模型未注册时抛出</exception>
public static TModel GetModel<TModel>(this IContextAware contextAware) where TModel : class, IModel public static TModel GetModel<TModel>(this IContextAware contextAware) where TModel : class, IModel
{ {
ArgumentNullException.ThrowIfNull(contextAware); if (contextAware is null)
{
throw new ArgumentNullException(nameof(contextAware));
}
var context = contextAware.GetContext(); var context = contextAware.GetContext();
return GetRequiredComponent(context, static architectureContext => architectureContext.GetModel<TModel>(), return GetRequiredComponent(context, static architectureContext => architectureContext.GetModel<TModel>(),
"Model"); "Model");
@ -72,7 +84,11 @@ public static class ContextAwareServiceExtensions
/// <exception cref="InvalidOperationException">当指定工具未注册时抛出</exception> /// <exception cref="InvalidOperationException">当指定工具未注册时抛出</exception>
public static TUtility GetUtility<TUtility>(this IContextAware contextAware) where TUtility : class, IUtility public static TUtility GetUtility<TUtility>(this IContextAware contextAware) where TUtility : class, IUtility
{ {
ArgumentNullException.ThrowIfNull(contextAware); if (contextAware is null)
{
throw new ArgumentNullException(nameof(contextAware));
}
var context = contextAware.GetContext(); var context = contextAware.GetContext();
return GetRequiredComponent(context, static architectureContext => architectureContext.GetUtility<TUtility>(), return GetRequiredComponent(context, static architectureContext => architectureContext.GetUtility<TUtility>(),
"Utility"); "Utility");
@ -92,7 +108,11 @@ public static class ContextAwareServiceExtensions
public static IReadOnlyList<TService> GetServices<TService>(this IContextAware contextAware) public static IReadOnlyList<TService> GetServices<TService>(this IContextAware contextAware)
where TService : class where TService : class
{ {
ArgumentNullException.ThrowIfNull(contextAware); if (contextAware is null)
{
throw new ArgumentNullException(nameof(contextAware));
}
var context = contextAware.GetContext(); var context = contextAware.GetContext();
return context.GetServices<TService>(); return context.GetServices<TService>();
} }
@ -107,7 +127,11 @@ public static class ContextAwareServiceExtensions
public static IReadOnlyList<TSystem> GetSystems<TSystem>(this IContextAware contextAware) public static IReadOnlyList<TSystem> GetSystems<TSystem>(this IContextAware contextAware)
where TSystem : class, ISystem where TSystem : class, ISystem
{ {
ArgumentNullException.ThrowIfNull(contextAware); if (contextAware is null)
{
throw new ArgumentNullException(nameof(contextAware));
}
var context = contextAware.GetContext(); var context = contextAware.GetContext();
return context.GetSystems<TSystem>(); return context.GetSystems<TSystem>();
} }
@ -122,7 +146,11 @@ public static class ContextAwareServiceExtensions
public static IReadOnlyList<TModel> GetModels<TModel>(this IContextAware contextAware) public static IReadOnlyList<TModel> GetModels<TModel>(this IContextAware contextAware)
where TModel : class, IModel where TModel : class, IModel
{ {
ArgumentNullException.ThrowIfNull(contextAware); if (contextAware is null)
{
throw new ArgumentNullException(nameof(contextAware));
}
var context = contextAware.GetContext(); var context = contextAware.GetContext();
return context.GetModels<TModel>(); return context.GetModels<TModel>();
} }
@ -137,7 +165,11 @@ public static class ContextAwareServiceExtensions
public static IReadOnlyList<TUtility> GetUtilities<TUtility>(this IContextAware contextAware) public static IReadOnlyList<TUtility> GetUtilities<TUtility>(this IContextAware contextAware)
where TUtility : class, IUtility where TUtility : class, IUtility
{ {
ArgumentNullException.ThrowIfNull(contextAware); if (contextAware is null)
{
throw new ArgumentNullException(nameof(contextAware));
}
var context = contextAware.GetContext(); var context = contextAware.GetContext();
return context.GetUtilities<TUtility>(); return context.GetUtilities<TUtility>();
} }
@ -152,7 +184,11 @@ public static class ContextAwareServiceExtensions
public static IReadOnlyList<TService> GetServicesByPriority<TService>(this IContextAware contextAware) public static IReadOnlyList<TService> GetServicesByPriority<TService>(this IContextAware contextAware)
where TService : class where TService : class
{ {
ArgumentNullException.ThrowIfNull(contextAware); if (contextAware is null)
{
throw new ArgumentNullException(nameof(contextAware));
}
var context = contextAware.GetContext(); var context = contextAware.GetContext();
return context.GetServicesByPriority<TService>(); return context.GetServicesByPriority<TService>();
} }
@ -167,7 +203,11 @@ public static class ContextAwareServiceExtensions
public static IReadOnlyList<TSystem> GetSystemsByPriority<TSystem>(this IContextAware contextAware) public static IReadOnlyList<TSystem> GetSystemsByPriority<TSystem>(this IContextAware contextAware)
where TSystem : class, ISystem where TSystem : class, ISystem
{ {
ArgumentNullException.ThrowIfNull(contextAware); if (contextAware is null)
{
throw new ArgumentNullException(nameof(contextAware));
}
var context = contextAware.GetContext(); var context = contextAware.GetContext();
return context.GetSystemsByPriority<TSystem>(); return context.GetSystemsByPriority<TSystem>();
} }
@ -182,7 +222,11 @@ public static class ContextAwareServiceExtensions
public static IReadOnlyList<TModel> GetModelsByPriority<TModel>(this IContextAware contextAware) public static IReadOnlyList<TModel> GetModelsByPriority<TModel>(this IContextAware contextAware)
where TModel : class, IModel where TModel : class, IModel
{ {
ArgumentNullException.ThrowIfNull(contextAware); if (contextAware is null)
{
throw new ArgumentNullException(nameof(contextAware));
}
var context = contextAware.GetContext(); var context = contextAware.GetContext();
return context.GetModelsByPriority<TModel>(); return context.GetModelsByPriority<TModel>();
} }
@ -197,7 +241,11 @@ public static class ContextAwareServiceExtensions
public static IReadOnlyList<TUtility> GetUtilitiesByPriority<TUtility>(this IContextAware contextAware) public static IReadOnlyList<TUtility> GetUtilitiesByPriority<TUtility>(this IContextAware contextAware)
where TUtility : class, IUtility where TUtility : class, IUtility
{ {
ArgumentNullException.ThrowIfNull(contextAware); if (contextAware is null)
{
throw new ArgumentNullException(nameof(contextAware));
}
var context = contextAware.GetContext(); var context = contextAware.GetContext();
return context.GetUtilitiesByPriority<TUtility>(); return context.GetUtilitiesByPriority<TUtility>();
} }
@ -206,7 +254,10 @@ public static class ContextAwareServiceExtensions
Func<IArchitectureContext, TComponent> resolver, string componentKind) Func<IArchitectureContext, TComponent> resolver, string componentKind)
where TComponent : class where TComponent : class
{ {
ArgumentNullException.ThrowIfNull(context); if (context is null)
{
throw new ArgumentNullException(nameof(context));
}
var component = resolver(context); var component = resolver(context);
return component ?? throw new InvalidOperationException($"{componentKind} {typeof(TComponent)} not registered"); return component ?? throw new InvalidOperationException($"{componentKind} {typeof(TComponent)} not registered");

View File

@ -27,7 +27,9 @@ public static class GuardExtensions
this T? value, this T? value,
[CallerArgumentExpression(nameof(value))] string? paramName = null) where T : class [CallerArgumentExpression(nameof(value))] string? paramName = null) where T : class
{ {
ArgumentNullException.ThrowIfNull(value, paramName); if (value is null)
throw new ArgumentNullException(paramName);
return value; return value;
} }
@ -51,7 +53,8 @@ public static class GuardExtensions
this string? value, this string? value,
[CallerArgumentExpression(nameof(value))] string? paramName = null) [CallerArgumentExpression(nameof(value))] string? paramName = null)
{ {
ArgumentNullException.ThrowIfNull(value, paramName); if (value is null)
throw new ArgumentNullException(paramName);
if (value.Length == 0) if (value.Length == 0)
throw new ArgumentException("字符串不能为空", paramName); throw new ArgumentException("字符串不能为空", paramName);
@ -79,7 +82,8 @@ public static class GuardExtensions
this string? value, this string? value,
[CallerArgumentExpression(nameof(value))] string? paramName = null) [CallerArgumentExpression(nameof(value))] string? paramName = null)
{ {
ArgumentNullException.ThrowIfNull(value, paramName); if (value is null)
throw new ArgumentNullException(paramName);
if (string.IsNullOrWhiteSpace(value)) if (string.IsNullOrWhiteSpace(value))
throw new ArgumentException("字符串不能为空或仅包含空白字符", paramName); throw new ArgumentException("字符串不能为空或仅包含空白字符", paramName);
@ -108,7 +112,8 @@ public static class GuardExtensions
this IEnumerable<T>? source, this IEnumerable<T>? source,
[CallerArgumentExpression(nameof(source))] string? paramName = null) [CallerArgumentExpression(nameof(source))] string? paramName = null)
{ {
ArgumentNullException.ThrowIfNull(source, paramName); if (source is null)
throw new ArgumentNullException(paramName);
if (!source.Any()) if (!source.Any())
throw new ArgumentException("集合不能为空", paramName); throw new ArgumentException("集合不能为空", paramName);

View File

@ -25,9 +25,14 @@ public static class NumericExtensions
/// </example> /// </example>
public static bool Between<T>(this T value, T min, T max, bool inclusive = true) where T : IComparable<T> public static bool Between<T>(this T value, T min, T max, bool inclusive = true) where T : IComparable<T>
{ {
ArgumentNullException.ThrowIfNull(value); if (value is null)
ArgumentNullException.ThrowIfNull(min); throw new ArgumentNullException(nameof(value));
ArgumentNullException.ThrowIfNull(max);
if (min is null)
throw new ArgumentNullException(nameof(min));
if (max is null)
throw new ArgumentNullException(nameof(max));
if (min.CompareTo(max) > 0) if (min.CompareTo(max) > 0)
throw new ArgumentException($"最小值 ({min}) 不能大于最大值 ({max})", nameof(min)); throw new ArgumentException($"最小值 ({min}) 不能大于最大值 ({max})", nameof(min));

View File

@ -27,8 +27,15 @@ public static class StoreEventBusExtensions
bool publishDispatches = true, bool publishDispatches = true,
bool publishStateChanges = true) bool publishStateChanges = true)
{ {
ArgumentNullException.ThrowIfNull(store); if (store is null)
ArgumentNullException.ThrowIfNull(eventBus); {
throw new ArgumentNullException(nameof(store));
}
if (eventBus is null)
{
throw new ArgumentNullException(nameof(eventBus));
}
IUnRegister? dispatchBridge = null; IUnRegister? dispatchBridge = null;
IUnRegister? stateBridge = null; IUnRegister? stateBridge = null;
@ -60,8 +67,15 @@ public static class StoreEventBusExtensions
/// <returns>用于移除 dispatch 桥接中间件的句柄。</returns> /// <returns>用于移除 dispatch 桥接中间件的句柄。</returns>
public static IUnRegister BridgeDispatchesToEventBus<TState>(this Store<TState> store, IEventBus eventBus) public static IUnRegister BridgeDispatchesToEventBus<TState>(this Store<TState> store, IEventBus eventBus)
{ {
ArgumentNullException.ThrowIfNull(store); if (store is null)
ArgumentNullException.ThrowIfNull(eventBus); {
throw new ArgumentNullException(nameof(store));
}
if (eventBus is null)
{
throw new ArgumentNullException(nameof(eventBus));
}
return store.RegisterMiddleware(new DispatchEventBusMiddleware<TState>(eventBus)); return store.RegisterMiddleware(new DispatchEventBusMiddleware<TState>(eventBus));
} }
@ -77,8 +91,15 @@ public static class StoreEventBusExtensions
public static IUnRegister BridgeStateChangesToEventBus<TState>(this IReadonlyStore<TState> store, public static IUnRegister BridgeStateChangesToEventBus<TState>(this IReadonlyStore<TState> store,
IEventBus eventBus) IEventBus eventBus)
{ {
ArgumentNullException.ThrowIfNull(store); if (store is null)
ArgumentNullException.ThrowIfNull(eventBus); {
throw new ArgumentNullException(nameof(store));
}
if (eventBus is null)
{
throw new ArgumentNullException(nameof(eventBus));
}
return store.Subscribe(state => return store.Subscribe(state =>
eventBus.Send(new StoreStateChangedEvent<TState>(state, DateTimeOffset.UtcNow))); eventBus.Send(new StoreStateChangedEvent<TState>(state, DateTimeOffset.UtcNow)));

View File

@ -38,8 +38,11 @@ public static class StringExtensions
/// </example> /// </example>
public static string Truncate(this string str, int maxLength, string suffix = "...") public static string Truncate(this string str, int maxLength, string suffix = "...")
{ {
ArgumentNullException.ThrowIfNull(str); if (str is null)
ArgumentNullException.ThrowIfNull(suffix); throw new ArgumentNullException(nameof(str));
if (suffix is null)
throw new ArgumentNullException(nameof(suffix));
if (maxLength < suffix.Length) if (maxLength < suffix.Length)
throw new ArgumentOutOfRangeException(nameof(maxLength), throw new ArgumentOutOfRangeException(nameof(maxLength),
@ -66,8 +69,11 @@ public static class StringExtensions
/// </example> /// </example>
public static string Join(this IEnumerable<string> values, string separator) public static string Join(this IEnumerable<string> values, string separator)
{ {
ArgumentNullException.ThrowIfNull(values); if (values is null)
ArgumentNullException.ThrowIfNull(separator); throw new ArgumentNullException(nameof(values));
if (separator is null)
throw new ArgumentNullException(nameof(separator));
return string.Join(separator, values); return string.Join(separator, values);
} }

View File

@ -39,7 +39,9 @@ public sealed class StoreBuilder<TState> : IStoreBuilder<TState>
/// <returns>当前构建器实例。</returns> /// <returns>当前构建器实例。</returns>
public IStoreBuilder<TState> UseMiddleware(IStoreMiddleware<TState> middleware) public IStoreBuilder<TState> UseMiddleware(IStoreMiddleware<TState> middleware)
{ {
ArgumentNullException.ThrowIfNull(middleware); if (middleware is null)
throw new ArgumentNullException(nameof(middleware));
_configurators.Add(store => store.UseMiddleware(middleware)); _configurators.Add(store => store.UseMiddleware(middleware));
return this; return this;
} }
@ -108,7 +110,9 @@ public sealed class StoreBuilder<TState> : IStoreBuilder<TState>
/// <returns>当前构建器实例。</returns> /// <returns>当前构建器实例。</returns>
public IStoreBuilder<TState> AddReducer<TAction>(Func<TState, TAction, TState> reducer) public IStoreBuilder<TState> AddReducer<TAction>(Func<TState, TAction, TState> reducer)
{ {
ArgumentNullException.ThrowIfNull(reducer); if (reducer is null)
throw new ArgumentNullException(nameof(reducer));
_configurators.Add(store => store.RegisterReducer(reducer)); _configurators.Add(store => store.RegisterReducer(reducer));
return this; return this;
} }
@ -121,7 +125,9 @@ public sealed class StoreBuilder<TState> : IStoreBuilder<TState>
/// <returns>当前构建器实例。</returns> /// <returns>当前构建器实例。</returns>
public IStoreBuilder<TState> AddReducer<TAction>(IReducer<TState, TAction> reducer) public IStoreBuilder<TState> AddReducer<TAction>(IReducer<TState, TAction> reducer)
{ {
ArgumentNullException.ThrowIfNull(reducer); if (reducer is null)
throw new ArgumentNullException(nameof(reducer));
_configurators.Add(store => store.RegisterReducer(reducer)); _configurators.Add(store => store.RegisterReducer(reducer));
return this; return this;
} }

View File

@ -82,7 +82,9 @@ public sealed class StoreSelection<TState, TSelected> : IReadonlyBindablePropert
/// <returns>用于取消订阅的句柄。</returns> /// <returns>用于取消订阅的句柄。</returns>
IUnRegister IEvent.Register(Action onEvent) IUnRegister IEvent.Register(Action onEvent)
{ {
ArgumentNullException.ThrowIfNull(onEvent); if (onEvent is null)
throw new ArgumentNullException(nameof(onEvent));
return Register(_ => onEvent()); return Register(_ => onEvent());
} }
@ -94,7 +96,8 @@ public sealed class StoreSelection<TState, TSelected> : IReadonlyBindablePropert
/// <exception cref="ArgumentNullException">当 <paramref name="onValueChanged"/> 为 <see langword="null"/> 时抛出。</exception> /// <exception cref="ArgumentNullException">当 <paramref name="onValueChanged"/> 为 <see langword="null"/> 时抛出。</exception>
public IUnRegister Register(Action<TSelected> onValueChanged) public IUnRegister Register(Action<TSelected> onValueChanged)
{ {
ArgumentNullException.ThrowIfNull(onValueChanged); if (onValueChanged is null)
throw new ArgumentNullException(nameof(onValueChanged));
var subscription = new SelectionListenerSubscription(onValueChanged); var subscription = new SelectionListenerSubscription(onValueChanged);
var shouldAttach = false; var shouldAttach = false;
@ -126,7 +129,8 @@ public sealed class StoreSelection<TState, TSelected> : IReadonlyBindablePropert
/// <exception cref="ArgumentNullException">当 <paramref name="action"/> 为 <see langword="null"/> 时抛出。</exception> /// <exception cref="ArgumentNullException">当 <paramref name="action"/> 为 <see langword="null"/> 时抛出。</exception>
public IUnRegister RegisterWithInitValue(Action<TSelected> action) public IUnRegister RegisterWithInitValue(Action<TSelected> action)
{ {
ArgumentNullException.ThrowIfNull(action); if (action is null)
throw new ArgumentNullException(nameof(action));
var subscription = new SelectionListenerSubscription(action) var subscription = new SelectionListenerSubscription(action)
{ {
@ -189,7 +193,8 @@ public sealed class StoreSelection<TState, TSelected> : IReadonlyBindablePropert
/// <exception cref="ArgumentNullException">当 <paramref name="onValueChanged"/> 为 <see langword="null"/> 时抛出。</exception> /// <exception cref="ArgumentNullException">当 <paramref name="onValueChanged"/> 为 <see langword="null"/> 时抛出。</exception>
public void UnRegister(Action<TSelected> onValueChanged) public void UnRegister(Action<TSelected> onValueChanged)
{ {
ArgumentNullException.ThrowIfNull(onValueChanged); if (onValueChanged is null)
throw new ArgumentNullException(nameof(onValueChanged));
SelectionListenerSubscription? subscriptionToRemove = null; SelectionListenerSubscription? subscriptionToRemove = null;