mirror of
https://github.com/GeWuYou/GFramework.git
synced 2026-03-25 13:33:28 +08:00
refactor(core): 重构协程扩展和函数式编程相关代码
- 优化 CommandCoroutineExtensions 中的代码格式和异常处理逻辑 - 简化 WaitForEvent 和 WaitForEventWithTimeout 中的EventData属性实现 - 调整 EventListenerScope 中的EventData属性访问器 - 重构 ControlExtensions 中 TakeIf 和 TakeUnless 方法的实现 - 优化 FunctionExtensions 中 Repeat 和 Partial 方法的代码结构 - 调整 PipeExtensions 和其他扩展类的文档注释格式 - 修改测试代码中的协程迭代和事件注册相关实现 - 优化 DataRepository 中的异步操作实现方式 = [release ci]
This commit is contained in:
parent
1d7fe998b9
commit
af583c101c
@ -14,13 +14,13 @@
|
|||||||
namespace GFramework.Core.Abstractions.data;
|
namespace GFramework.Core.Abstractions.data;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 定义从指定类型数据源加载数据的接口
|
/// 定义从指定类型数据源加载数据的接口
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <typeparam name="T">数据源的类型</typeparam>
|
/// <typeparam name="T">数据源的类型</typeparam>
|
||||||
public interface ILoadableFrom<in T>
|
public interface ILoadableFrom<in T>
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 从指定的数据源加载数据到当前对象
|
/// 从指定的数据源加载数据到当前对象
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="source">用作数据源的对象,类型为T</param>
|
/// <param name="source">用作数据源的对象,类型为T</param>
|
||||||
void LoadFrom(T source);
|
void LoadFrom(T source);
|
||||||
|
|||||||
@ -25,8 +25,16 @@ public class CommandCoroutineExtensionsTests
|
|||||||
private class TestCommand : IAsyncCommand
|
private class TestCommand : IAsyncCommand
|
||||||
{
|
{
|
||||||
private IArchitectureContext? _context;
|
private IArchitectureContext? _context;
|
||||||
public void SetContext(IArchitectureContext context) => _context = context;
|
|
||||||
public IArchitectureContext GetContext() => _context!;
|
public void SetContext(IArchitectureContext context)
|
||||||
|
{
|
||||||
|
_context = context;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IArchitectureContext GetContext()
|
||||||
|
{
|
||||||
|
return _context!;
|
||||||
|
}
|
||||||
|
|
||||||
public Task ExecuteAsync()
|
public Task ExecuteAsync()
|
||||||
{
|
{
|
||||||
@ -47,7 +55,7 @@ public class CommandCoroutineExtensionsTests
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
private class TestContextAware : IContextAware
|
private class TestContextAware : IContextAware
|
||||||
{
|
{
|
||||||
public Mock<IArchitectureContext> _mockContext = new();
|
public readonly Mock<IArchitectureContext> _mockContext = new();
|
||||||
|
|
||||||
public IArchitectureContext GetContext()
|
public IArchitectureContext GetContext()
|
||||||
{
|
{
|
||||||
@ -78,13 +86,9 @@ public class CommandCoroutineExtensionsTests
|
|||||||
|
|
||||||
// 迭代协程直到完成
|
// 迭代协程直到完成
|
||||||
while (coroutine.MoveNext())
|
while (coroutine.MoveNext())
|
||||||
{
|
|
||||||
if (coroutine.Current is WaitForTask)
|
if (coroutine.Current is WaitForTask)
|
||||||
{
|
|
||||||
// 等待任务完成
|
// 等待任务完成
|
||||||
await Task.Delay(10);
|
await Task.Delay(10);
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Assert.That(capturedException, Is.Null);
|
Assert.That(capturedException, Is.Null);
|
||||||
}
|
}
|
||||||
@ -109,13 +113,9 @@ public class CommandCoroutineExtensionsTests
|
|||||||
|
|
||||||
// 迭代协程直到完成
|
// 迭代协程直到完成
|
||||||
while (coroutine.MoveNext())
|
while (coroutine.MoveNext())
|
||||||
{
|
|
||||||
if (coroutine.Current is WaitForTask)
|
if (coroutine.Current is WaitForTask)
|
||||||
{
|
|
||||||
// 等待任务完成
|
// 等待任务完成
|
||||||
await Task.Delay(10);
|
await Task.Delay(10);
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Assert.That(capturedException, Is.Not.Null);
|
Assert.That(capturedException, Is.Not.Null);
|
||||||
// 异常被包装为 AggregateException
|
// 异常被包装为 AggregateException
|
||||||
@ -140,17 +140,13 @@ public class CommandCoroutineExtensionsTests
|
|||||||
.Returns(Task.FromException(expectedException));
|
.Returns(Task.FromException(expectedException));
|
||||||
|
|
||||||
// 使用null作为错误处理程序
|
// 使用null作为错误处理程序
|
||||||
var coroutine = contextAware.SendCommandCoroutineWithErrorHandler(command, null);
|
var coroutine = contextAware.SendCommandCoroutineWithErrorHandler(command);
|
||||||
|
|
||||||
// 迭代协程直到完成
|
// 迭代协程直到完成
|
||||||
while (coroutine.MoveNext())
|
while (coroutine.MoveNext())
|
||||||
{
|
|
||||||
if (coroutine.Current is WaitForTask)
|
if (coroutine.Current is WaitForTask)
|
||||||
{
|
|
||||||
// 等待任务完成
|
// 等待任务完成
|
||||||
await Task.Delay(10);
|
await Task.Delay(10);
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 应该不会抛出异常
|
// 应该不会抛出异常
|
||||||
Assert.Pass();
|
Assert.Pass();
|
||||||
@ -172,7 +168,7 @@ public class CommandCoroutineExtensionsTests
|
|||||||
var unRegisterMock = new Mock<IUnRegister>();
|
var unRegisterMock = new Mock<IUnRegister>();
|
||||||
|
|
||||||
Action<TestEvent>? eventCallback = null;
|
Action<TestEvent>? eventCallback = null;
|
||||||
eventBusMock.Setup(bus => bus.Register<TestEvent>(It.IsAny<Action<TestEvent>>()))
|
eventBusMock.Setup(bus => bus.Register(It.IsAny<Action<TestEvent>>()))
|
||||||
.Returns(unRegisterMock.Object)
|
.Returns(unRegisterMock.Object)
|
||||||
.Callback<Action<TestEvent>>(callback => eventCallback = callback);
|
.Callback<Action<TestEvent>>(callback => eventCallback = callback);
|
||||||
|
|
||||||
@ -196,10 +192,7 @@ public class CommandCoroutineExtensionsTests
|
|||||||
|
|
||||||
// 启动协程并等待命令执行完成
|
// 启动协程并等待命令执行完成
|
||||||
coroutine.MoveNext(); // 进入命令发送阶段
|
coroutine.MoveNext(); // 进入命令发送阶段
|
||||||
if (coroutine.Current is WaitForTask)
|
if (coroutine.Current is WaitForTask) await Task.Delay(10); // 等待命令任务完成
|
||||||
{
|
|
||||||
await Task.Delay(10); // 等待命令任务完成
|
|
||||||
}
|
|
||||||
|
|
||||||
// 此时协程应该在等待事件
|
// 此时协程应该在等待事件
|
||||||
Assert.That(coroutine.MoveNext(), Is.True); // 等待事件阶段
|
Assert.That(coroutine.MoveNext(), Is.True); // 等待事件阶段
|
||||||
@ -252,13 +245,9 @@ public class CommandCoroutineExtensionsTests
|
|||||||
|
|
||||||
// 运行协程直到完成
|
// 运行协程直到完成
|
||||||
while (coroutine.MoveNext())
|
while (coroutine.MoveNext())
|
||||||
{
|
|
||||||
if (coroutine.Current is WaitForEventWithTimeout<TestEvent> timeoutWait)
|
if (coroutine.Current is WaitForEventWithTimeout<TestEvent> timeoutWait)
|
||||||
{
|
|
||||||
// 模拟超时
|
// 模拟超时
|
||||||
timeoutWait.Update(0.2); // 更新时间超过超时限制
|
timeoutWait.Update(0.2); // 更新时间超过超时限制
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -292,15 +281,11 @@ public class CommandCoroutineExtensionsTests
|
|||||||
|
|
||||||
// 使用null作为事件回调
|
// 使用null作为事件回调
|
||||||
var coroutine = contextAware.SendCommandAndWaitEventCoroutine<TestCommand, TestEvent>(
|
var coroutine = contextAware.SendCommandAndWaitEventCoroutine<TestCommand, TestEvent>(
|
||||||
command,
|
command); // null回调
|
||||||
null); // null回调
|
|
||||||
|
|
||||||
// 启动协程
|
// 启动协程
|
||||||
coroutine.MoveNext(); // 进入命令发送阶段
|
coroutine.MoveNext(); // 进入命令发送阶段
|
||||||
if (coroutine.Current is WaitForTask)
|
if (coroutine.Current is WaitForTask) await Task.Delay(10); // 等待命令任务完成
|
||||||
{
|
|
||||||
await Task.Delay(10); // 等待命令任务完成
|
|
||||||
}
|
|
||||||
|
|
||||||
// 触发事件
|
// 触发事件
|
||||||
var testEvent = new TestEvent { Data = "TestData" };
|
var testEvent = new TestEvent { Data = "TestData" };
|
||||||
@ -343,10 +328,7 @@ public class CommandCoroutineExtensionsTests
|
|||||||
|
|
||||||
// 启动协程 - 命令失败时协程仍然继续
|
// 启动协程 - 命令失败时协程仍然继续
|
||||||
coroutine.MoveNext(); // 进入命令发送阶段
|
coroutine.MoveNext(); // 进入命令发送阶段
|
||||||
if (coroutine.Current is WaitForTask)
|
if (coroutine.Current is WaitForTask) await Task.Delay(10); // 等待命令任务完成
|
||||||
{
|
|
||||||
await Task.Delay(10); // 等待命令任务完成
|
|
||||||
}
|
|
||||||
|
|
||||||
// 命令执行失败后,协程继续执行
|
// 命令执行失败后,协程继续执行
|
||||||
Assert.Pass();
|
Assert.Pass();
|
||||||
@ -384,7 +366,7 @@ public class CommandCoroutineExtensionsTests
|
|||||||
var eventBusMock = new Mock<IEventBus>();
|
var eventBusMock = new Mock<IEventBus>();
|
||||||
var unRegisterMock = new Mock<IUnRegister>();
|
var unRegisterMock = new Mock<IUnRegister>();
|
||||||
|
|
||||||
eventBusMock.Setup(bus => bus.Register<TestEvent>(It.IsAny<Action<TestEvent>>()))
|
eventBusMock.Setup(bus => bus.Register(It.IsAny<Action<TestEvent>>()))
|
||||||
.Returns(unRegisterMock.Object);
|
.Returns(unRegisterMock.Object);
|
||||||
|
|
||||||
// 设置上下文服务以返回事件总线
|
// 设置上下文服务以返回事件总线
|
||||||
|
|||||||
@ -50,10 +50,7 @@ public class CoroutineComposeExtensionsTests
|
|||||||
var combined = first.Then(() => executionOrder.Add("action"));
|
var combined = first.Then(() => executionOrder.Add("action"));
|
||||||
|
|
||||||
// 执行组合协程
|
// 执行组合协程
|
||||||
while (combined.MoveNext())
|
while (combined.MoveNext()) combined.Current.Update(0.016);
|
||||||
{
|
|
||||||
combined.Current.Update(0.016);
|
|
||||||
}
|
|
||||||
|
|
||||||
Assert.That(executionOrder.Count, Is.EqualTo(3));
|
Assert.That(executionOrder.Count, Is.EqualTo(3));
|
||||||
Assert.That(executionOrder[0], Is.EqualTo("coroutine"));
|
Assert.That(executionOrder[0], Is.EqualTo("coroutine"));
|
||||||
@ -112,10 +109,7 @@ public class CoroutineComposeExtensionsTests
|
|||||||
.Then(() => executionOrder.Add(2))
|
.Then(() => executionOrder.Add(2))
|
||||||
.Then(() => executionOrder.Add(3));
|
.Then(() => executionOrder.Add(3));
|
||||||
|
|
||||||
while (combined.MoveNext())
|
while (combined.MoveNext()) combined.Current.Update(0.016);
|
||||||
{
|
|
||||||
combined.Current.Update(0.016);
|
|
||||||
}
|
|
||||||
|
|
||||||
Assert.That(executionOrder, Is.EqualTo([1, 2, 3]));
|
Assert.That(executionOrder, Is.EqualTo([1, 2, 3]));
|
||||||
}
|
}
|
||||||
@ -162,10 +156,7 @@ public class CoroutineComposeExtensionsTests
|
|||||||
var second = CreateTestCoroutine(2, () => executionOrder.Add("second"));
|
var second = CreateTestCoroutine(2, () => executionOrder.Add("second"));
|
||||||
var combined = first.Then(second);
|
var combined = first.Then(second);
|
||||||
|
|
||||||
while (combined.MoveNext())
|
while (combined.MoveNext()) combined.Current.Update(0.016);
|
||||||
{
|
|
||||||
combined.Current.Update(0.016);
|
|
||||||
}
|
|
||||||
|
|
||||||
Assert.That(executionOrder.Count, Is.EqualTo(4));
|
Assert.That(executionOrder.Count, Is.EqualTo(4));
|
||||||
Assert.That(executionOrder[0], Is.EqualTo("first"));
|
Assert.That(executionOrder[0], Is.EqualTo("first"));
|
||||||
@ -206,10 +197,7 @@ public class CoroutineComposeExtensionsTests
|
|||||||
var second = CreateTestCoroutine(0);
|
var second = CreateTestCoroutine(0);
|
||||||
var combined = first.Then(second);
|
var combined = first.Then(second);
|
||||||
|
|
||||||
while (combined.MoveNext())
|
while (combined.MoveNext()) combined.Current.Update(0.016);
|
||||||
{
|
|
||||||
combined.Current.Update(0.016);
|
|
||||||
}
|
|
||||||
|
|
||||||
Assert.That(firstExecuteCount, Is.EqualTo(2));
|
Assert.That(firstExecuteCount, Is.EqualTo(2));
|
||||||
}
|
}
|
||||||
@ -262,10 +250,7 @@ public class CoroutineComposeExtensionsTests
|
|||||||
|
|
||||||
var combined = first.Then(second).Then(third);
|
var combined = first.Then(second).Then(third);
|
||||||
|
|
||||||
while (combined.MoveNext())
|
while (combined.MoveNext()) combined.Current.Update(0.016);
|
||||||
{
|
|
||||||
combined.Current.Update(0.016);
|
|
||||||
}
|
|
||||||
|
|
||||||
Assert.That(executionOrder, Is.EqualTo(new[] { 1, 2, 3 }));
|
Assert.That(executionOrder, Is.EqualTo(new[] { 1, 2, 3 }));
|
||||||
}
|
}
|
||||||
@ -286,10 +271,7 @@ public class CoroutineComposeExtensionsTests
|
|||||||
.Then(second)
|
.Then(second)
|
||||||
.Then(() => executionOrder.Add("action2"));
|
.Then(() => executionOrder.Add("action2"));
|
||||||
|
|
||||||
while (combined.MoveNext())
|
while (combined.MoveNext()) combined.Current.Update(0.016);
|
||||||
{
|
|
||||||
combined.Current.Update(0.016);
|
|
||||||
}
|
|
||||||
|
|
||||||
Assert.That(executionOrder, Is.EqualTo(new[] { "coroutine1", "action1", "coroutine2", "action2" }));
|
Assert.That(executionOrder, Is.EqualTo(new[] { "coroutine1", "action1", "coroutine2", "action2" }));
|
||||||
}
|
}
|
||||||
@ -339,10 +321,7 @@ public class CoroutineComposeExtensionsTests
|
|||||||
coroutine = coroutine.Then(nextCoroutine);
|
coroutine = coroutine.Then(nextCoroutine);
|
||||||
}
|
}
|
||||||
|
|
||||||
while (coroutine.MoveNext())
|
while (coroutine.MoveNext()) coroutine.Current.Update(0.016);
|
||||||
{
|
|
||||||
coroutine.Current.Update(0.016);
|
|
||||||
}
|
|
||||||
|
|
||||||
Assert.That(count, Is.EqualTo(11));
|
Assert.That(count, Is.EqualTo(11));
|
||||||
}
|
}
|
||||||
|
|||||||
@ -443,7 +443,7 @@ public class CoroutineHelperTests
|
|||||||
public void RepeatCallForever_Should_Execute_Forever_When_ShouldContinue_Is_Null()
|
public void RepeatCallForever_Should_Execute_Forever_When_ShouldContinue_Is_Null()
|
||||||
{
|
{
|
||||||
var callCount = 0;
|
var callCount = 0;
|
||||||
var coroutine = CoroutineHelper.RepeatCallForever(0.1, () => callCount++, (Func<bool>?)null);
|
var coroutine = CoroutineHelper.RepeatCallForever(0.1, () => callCount++);
|
||||||
|
|
||||||
for (var i = 0; i < 5; i++)
|
for (var i = 0; i < 5; i++)
|
||||||
{
|
{
|
||||||
|
|||||||
@ -23,9 +23,21 @@ public class QueryCoroutineExtensionsTests
|
|||||||
{
|
{
|
||||||
private IArchitectureContext? _context;
|
private IArchitectureContext? _context;
|
||||||
public string QueryData { get; set; } = string.Empty;
|
public string QueryData { get; set; } = string.Empty;
|
||||||
public void SetContext(IArchitectureContext context) => _context = context;
|
|
||||||
public IArchitectureContext GetContext() => _context!;
|
public void SetContext(IArchitectureContext context)
|
||||||
public string Do() => QueryData;
|
{
|
||||||
|
_context = context;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IArchitectureContext GetContext()
|
||||||
|
{
|
||||||
|
return _context!;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string Do()
|
||||||
|
{
|
||||||
|
return QueryData;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -33,7 +45,7 @@ public class QueryCoroutineExtensionsTests
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
private class TestContextAware : IContextAware
|
private class TestContextAware : IContextAware
|
||||||
{
|
{
|
||||||
public Mock<IArchitectureContext> _mockContext = new Mock<IArchitectureContext>();
|
public readonly Mock<IArchitectureContext> _mockContext = new();
|
||||||
|
|
||||||
public IArchitectureContext GetContext()
|
public IArchitectureContext GetContext()
|
||||||
{
|
{
|
||||||
@ -58,7 +70,7 @@ public class QueryCoroutineExtensionsTests
|
|||||||
|
|
||||||
// 设置上下文发送查询的模拟行为
|
// 设置上下文发送查询的模拟行为
|
||||||
contextAware._mockContext
|
contextAware._mockContext
|
||||||
.Setup(ctx => ctx.SendQuery<string>(It.IsAny<TestQuery>()))
|
.Setup(ctx => ctx.SendQuery(It.IsAny<TestQuery>()))
|
||||||
.Returns("TestResult");
|
.Returns("TestResult");
|
||||||
|
|
||||||
var coroutine = contextAware.SendQueryCoroutine<TestQuery, string>(query, result =>
|
var coroutine = contextAware.SendQueryCoroutine<TestQuery, string>(query, result =>
|
||||||
@ -90,7 +102,7 @@ public class QueryCoroutineExtensionsTests
|
|||||||
|
|
||||||
// 设置上下文发送查询的模拟行为
|
// 设置上下文发送查询的模拟行为
|
||||||
contextAware._mockContext
|
contextAware._mockContext
|
||||||
.Setup(ctx => ctx.SendQuery<bool>(It.IsAny<IntQuery>()))
|
.Setup(ctx => ctx.SendQuery(It.IsAny<IntQuery>()))
|
||||||
.Returns(true);
|
.Returns(true);
|
||||||
|
|
||||||
var coroutine = contextAware.SendQueryCoroutine<IntQuery, bool>(query, result =>
|
var coroutine = contextAware.SendQueryCoroutine<IntQuery, bool>(query, result =>
|
||||||
@ -118,7 +130,7 @@ public class QueryCoroutineExtensionsTests
|
|||||||
|
|
||||||
// 设置上下文发送查询的模拟行为
|
// 设置上下文发送查询的模拟行为
|
||||||
contextAware._mockContext
|
contextAware._mockContext
|
||||||
.Setup(ctx => ctx.SendQuery<string>(It.IsAny<TestQuery>()))
|
.Setup(ctx => ctx.SendQuery(It.IsAny<TestQuery>()))
|
||||||
.Returns("TestResult");
|
.Returns("TestResult");
|
||||||
|
|
||||||
// 使用null作为结果回调,应该抛出NullReferenceException
|
// 使用null作为结果回调,应该抛出NullReferenceException
|
||||||
@ -141,7 +153,7 @@ public class QueryCoroutineExtensionsTests
|
|||||||
|
|
||||||
// 设置上下文发送查询的模拟行为
|
// 设置上下文发送查询的模拟行为
|
||||||
contextAware._mockContext
|
contextAware._mockContext
|
||||||
.Setup(ctx => ctx.SendQuery<string>(It.IsAny<TestQuery>()))
|
.Setup(ctx => ctx.SendQuery(It.IsAny<TestQuery>()))
|
||||||
.Returns("ProcessedResult");
|
.Returns("ProcessedResult");
|
||||||
|
|
||||||
var coroutine = contextAware.SendQueryCoroutine<TestQuery, string>(query, result =>
|
var coroutine = contextAware.SendQueryCoroutine<TestQuery, string>(query, result =>
|
||||||
@ -168,7 +180,7 @@ public class QueryCoroutineExtensionsTests
|
|||||||
|
|
||||||
// 设置上下文发送查询的模拟行为
|
// 设置上下文发送查询的模拟行为
|
||||||
contextAware._mockContext
|
contextAware._mockContext
|
||||||
.Setup(ctx => ctx.SendQuery<string>(It.IsAny<TestQuery>()))
|
.Setup(ctx => ctx.SendQuery(It.IsAny<TestQuery>()))
|
||||||
.Returns("TestResult");
|
.Returns("TestResult");
|
||||||
|
|
||||||
var coroutine = contextAware.SendQueryCoroutine<TestQuery, string>(query, result => { });
|
var coroutine = contextAware.SendQueryCoroutine<TestQuery, string>(query, result => { });
|
||||||
@ -189,7 +201,7 @@ public class QueryCoroutineExtensionsTests
|
|||||||
|
|
||||||
// 设置上下文发送查询的模拟行为,让它抛出异常
|
// 设置上下文发送查询的模拟行为,让它抛出异常
|
||||||
contextAware._mockContext
|
contextAware._mockContext
|
||||||
.Setup(ctx => ctx.SendQuery<string>(It.IsAny<TestQuery>()))
|
.Setup(ctx => ctx.SendQuery(It.IsAny<TestQuery>()))
|
||||||
.Throws(expectedException);
|
.Throws(expectedException);
|
||||||
|
|
||||||
// 由于SendQueryCoroutine会直接执行查询,这可能导致异常
|
// 由于SendQueryCoroutine会直接执行查询,这可能导致异常
|
||||||
@ -216,7 +228,7 @@ public class QueryCoroutineExtensionsTests
|
|||||||
|
|
||||||
// 设置上下文发送查询的模拟行为,并捕获传入的查询参数
|
// 设置上下文发送查询的模拟行为,并捕获传入的查询参数
|
||||||
contextAware._mockContext
|
contextAware._mockContext
|
||||||
.Setup(ctx => ctx.SendQuery<string>(It.IsAny<TestQuery>()))
|
.Setup(ctx => ctx.SendQuery(It.IsAny<TestQuery>()))
|
||||||
.Returns((IQuery<string> q) =>
|
.Returns((IQuery<string> q) =>
|
||||||
{
|
{
|
||||||
capturedQuery = (TestQuery)q;
|
capturedQuery = (TestQuery)q;
|
||||||
@ -258,7 +270,7 @@ public class QueryCoroutineExtensionsTests
|
|||||||
|
|
||||||
// 设置上下文发送查询的模拟行为
|
// 设置上下文发送查询的模拟行为
|
||||||
contextAware._mockContext
|
contextAware._mockContext
|
||||||
.Setup(ctx => ctx.SendQuery<ComplexResult>(It.IsAny<ComplexQuery>()))
|
.Setup(ctx => ctx.SendQuery(It.IsAny<ComplexQuery>()))
|
||||||
.Returns(expectedResult);
|
.Returns(expectedResult);
|
||||||
|
|
||||||
var coroutine =
|
var coroutine =
|
||||||
@ -284,7 +296,7 @@ public class QueryCoroutineExtensionsTests
|
|||||||
|
|
||||||
// 设置上下文发送查询的模拟行为,返回空字符串
|
// 设置上下文发送查询的模拟行为,返回空字符串
|
||||||
contextAware._mockContext
|
contextAware._mockContext
|
||||||
.Setup(ctx => ctx.SendQuery<string>(It.IsAny<TestQuery>()))
|
.Setup(ctx => ctx.SendQuery(It.IsAny<TestQuery>()))
|
||||||
.Returns(string.Empty);
|
.Returns(string.Empty);
|
||||||
|
|
||||||
var coroutine =
|
var coroutine =
|
||||||
@ -302,12 +314,12 @@ public class QueryCoroutineExtensionsTests
|
|||||||
public void SendQueryCoroutine_Should_Handle_Null_Result()
|
public void SendQueryCoroutine_Should_Handle_Null_Result()
|
||||||
{
|
{
|
||||||
var query = new TestQuery { QueryData = "TestQueryData" };
|
var query = new TestQuery { QueryData = "TestQueryData" };
|
||||||
string? receivedResult = "initial";
|
var receivedResult = "initial";
|
||||||
var contextAware = new TestContextAware();
|
var contextAware = new TestContextAware();
|
||||||
|
|
||||||
// 设置上下文发送查询的模拟行为,返回null
|
// 设置上下文发送查询的模拟行为,返回null
|
||||||
contextAware._mockContext
|
contextAware._mockContext
|
||||||
.Setup(ctx => ctx.SendQuery<string>(It.IsAny<TestQuery>()))
|
.Setup(ctx => ctx.SendQuery(It.IsAny<TestQuery>()))
|
||||||
.Returns((string)null!);
|
.Returns((string)null!);
|
||||||
|
|
||||||
var coroutine =
|
var coroutine =
|
||||||
@ -326,9 +338,21 @@ internal class IntQuery : IQuery<bool>
|
|||||||
{
|
{
|
||||||
private IArchitectureContext? _context;
|
private IArchitectureContext? _context;
|
||||||
public int Value { get; set; }
|
public int Value { get; set; }
|
||||||
public void SetContext(IArchitectureContext context) => _context = context;
|
|
||||||
public IArchitectureContext GetContext() => _context!;
|
public void SetContext(IArchitectureContext context)
|
||||||
public bool Do() => Value > 0;
|
{
|
||||||
|
_context = context;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IArchitectureContext GetContext()
|
||||||
|
{
|
||||||
|
return _context!;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Do()
|
||||||
|
{
|
||||||
|
return Value > 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -338,11 +362,23 @@ internal class ComplexQuery : IQuery<ComplexResult>
|
|||||||
{
|
{
|
||||||
private IArchitectureContext? _context;
|
private IArchitectureContext? _context;
|
||||||
public string Name { get; set; } = string.Empty;
|
public string Name { get; set; } = string.Empty;
|
||||||
public List<int> Values { get; set; } = new List<int>();
|
public List<int> Values { get; set; } = new();
|
||||||
public Dictionary<string, object> Metadata { get; set; } = new Dictionary<string, object>();
|
public Dictionary<string, object> Metadata { get; set; } = new();
|
||||||
public void SetContext(IArchitectureContext context) => _context = context;
|
|
||||||
public IArchitectureContext GetContext() => _context!;
|
public void SetContext(IArchitectureContext context)
|
||||||
public ComplexResult Do() => new ComplexResult { ProcessedName = Name, Sum = Values.Sum(), Count = Values.Count };
|
{
|
||||||
|
_context = context;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IArchitectureContext GetContext()
|
||||||
|
{
|
||||||
|
return _context!;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ComplexResult Do()
|
||||||
|
{
|
||||||
|
return new ComplexResult { ProcessedName = Name, Sum = Values.Sum(), Count = Values.Count };
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@ -217,7 +217,7 @@ public class EventListenerScopeTests
|
|||||||
var eventBusMock = new Mock<IEventBus>();
|
var eventBusMock = new Mock<IEventBus>();
|
||||||
var unRegisterMock = new Mock<IUnRegister>();
|
var unRegisterMock = new Mock<IUnRegister>();
|
||||||
|
|
||||||
eventBusMock.Setup(x => x.Register<int>(It.IsAny<Action<int>>()))
|
eventBusMock.Setup(x => x.Register(It.IsAny<Action<int>>()))
|
||||||
.Returns(unRegisterMock.Object)
|
.Returns(unRegisterMock.Object)
|
||||||
.Callback<Action<int>>(action => registeredAction = action);
|
.Callback<Action<int>>(action => registeredAction = action);
|
||||||
|
|
||||||
@ -242,7 +242,7 @@ public class EventListenerScopeTests
|
|||||||
var eventBusMock = new Mock<IEventBus>();
|
var eventBusMock = new Mock<IEventBus>();
|
||||||
var unRegisterMock = new Mock<IUnRegister>();
|
var unRegisterMock = new Mock<IUnRegister>();
|
||||||
|
|
||||||
eventBusMock.Setup(x => x.Register<StructEvent>(It.IsAny<Action<StructEvent>>()))
|
eventBusMock.Setup(x => x.Register(It.IsAny<Action<StructEvent>>()))
|
||||||
.Returns(unRegisterMock.Object)
|
.Returns(unRegisterMock.Object)
|
||||||
.Callback<Action<StructEvent>>(action => registeredAction = action);
|
.Callback<Action<StructEvent>>(action => registeredAction = action);
|
||||||
|
|
||||||
@ -268,7 +268,7 @@ public class EventListenerScopeTests
|
|||||||
var eventBusMock = new Mock<IEventBus>();
|
var eventBusMock = new Mock<IEventBus>();
|
||||||
var unRegisterMock = new Mock<IUnRegister>();
|
var unRegisterMock = new Mock<IUnRegister>();
|
||||||
|
|
||||||
eventBusMock.Setup(x => x.Register<TestEvent>(It.IsAny<Action<TestEvent>>()))
|
eventBusMock.Setup(x => x.Register(It.IsAny<Action<TestEvent>>()))
|
||||||
.Returns(unRegisterMock.Object)
|
.Returns(unRegisterMock.Object)
|
||||||
.Callback<Action<TestEvent>>(action => registeredAction = action);
|
.Callback<Action<TestEvent>>(action => registeredAction = action);
|
||||||
|
|
||||||
@ -290,7 +290,7 @@ public class EventListenerScopeTests
|
|||||||
{
|
{
|
||||||
var eventBusMock = new Mock<IEventBus>();
|
var eventBusMock = new Mock<IEventBus>();
|
||||||
var unRegisterMock = new Mock<IUnRegister>();
|
var unRegisterMock = new Mock<IUnRegister>();
|
||||||
eventBusMock.Setup(x => x.Register<TestEvent>(It.IsAny<Action<TestEvent>>()))
|
eventBusMock.Setup(x => x.Register(It.IsAny<Action<TestEvent>>()))
|
||||||
.Returns(unRegisterMock.Object);
|
.Returns(unRegisterMock.Object);
|
||||||
|
|
||||||
var scope = new EventListenerScope<TestEvent>(eventBusMock.Object);
|
var scope = new EventListenerScope<TestEvent>(eventBusMock.Object);
|
||||||
|
|||||||
@ -4,19 +4,19 @@ using NUnit.Framework;
|
|||||||
namespace GFramework.Core.Tests.functional.control;
|
namespace GFramework.Core.Tests.functional.control;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// ControlExtensions扩展方法测试类,用于验证控制流函数式编程扩展方法的正确性
|
/// ControlExtensions扩展方法测试类,用于验证控制流函数式编程扩展方法的正确性
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[TestFixture]
|
[TestFixture]
|
||||||
public class ControlExtensionsTests
|
public class ControlExtensionsTests
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 测试TakeIf方法 - 验证条件为真时返回原值
|
/// 测试TakeIf方法 - 验证条件为真时返回原值
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Test]
|
[Test]
|
||||||
public void TakeIf_Should_Return_Value_When_Condition_Is_True()
|
public void TakeIf_Should_Return_Value_When_Condition_Is_True()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
string str = "Hello";
|
var str = "Hello";
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var result = str.TakeIf(s => s.Length > 3);
|
var result = str.TakeIf(s => s.Length > 3);
|
||||||
@ -26,13 +26,13 @@ public class ControlExtensionsTests
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 测试TakeIf方法 - 验证条件为假时返回null
|
/// 测试TakeIf方法 - 验证条件为假时返回null
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Test]
|
[Test]
|
||||||
public void TakeIf_Should_Return_Null_When_Condition_Is_False()
|
public void TakeIf_Should_Return_Null_When_Condition_Is_False()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
string str = "Hi";
|
var str = "Hi";
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var result = str.TakeIf(s => s.Length > 3);
|
var result = str.TakeIf(s => s.Length > 3);
|
||||||
@ -42,13 +42,13 @@ public class ControlExtensionsTests
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 测试TakeUnless方法 - 验证条件为假时返回原值
|
/// 测试TakeUnless方法 - 验证条件为假时返回原值
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Test]
|
[Test]
|
||||||
public void TakeUnless_Should_Return_Value_When_Condition_Is_False()
|
public void TakeUnless_Should_Return_Value_When_Condition_Is_False()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
string str = "Hi";
|
var str = "Hi";
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var result = str.TakeUnless(s => s.Length > 3);
|
var result = str.TakeUnless(s => s.Length > 3);
|
||||||
@ -58,13 +58,13 @@ public class ControlExtensionsTests
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 测试TakeUnless方法 - 验证条件为真时返回null
|
/// 测试TakeUnless方法 - 验证条件为真时返回null
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Test]
|
[Test]
|
||||||
public void TakeUnless_Should_Return_Null_When_Condition_Is_True()
|
public void TakeUnless_Should_Return_Null_When_Condition_Is_True()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
string str = "Hello";
|
var str = "Hello";
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var result = str.TakeUnless(s => s.Length > 3);
|
var result = str.TakeUnless(s => s.Length > 3);
|
||||||
|
|||||||
@ -4,14 +4,14 @@ using NUnit.Framework;
|
|||||||
namespace GFramework.Core.Tests.functional.functions;
|
namespace GFramework.Core.Tests.functional.functions;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// FunctionExtensions扩展方法测试类,用于验证高级函数式编程扩展方法的正确性
|
/// FunctionExtensions扩展方法测试类,用于验证高级函数式编程扩展方法的正确性
|
||||||
/// 包括柯里化、偏函数应用、重复执行、安全执行和缓存等功能的测试
|
/// 包括柯里化、偏函数应用、重复执行、安全执行和缓存等功能的测试
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[TestFixture]
|
[TestFixture]
|
||||||
public class FunctionExtensionsTests
|
public class FunctionExtensionsTests
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 测试Partial方法 - 验证部分应用函数功能
|
/// 测试Partial方法 - 验证部分应用函数功能
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Test]
|
[Test]
|
||||||
public void Partial_Should_Fix_First_Argument_Of_Binary_Function()
|
public void Partial_Should_Fix_First_Argument_Of_Binary_Function()
|
||||||
@ -28,7 +28,7 @@ public class FunctionExtensionsTests
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 测试Repeat方法 - 验证重复执行函数功能
|
/// 测试Repeat方法 - 验证重复执行函数功能
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Test]
|
[Test]
|
||||||
public void Repeat_Should_Execute_Function_N_Times()
|
public void Repeat_Should_Execute_Function_N_Times()
|
||||||
|
|||||||
@ -4,14 +4,14 @@ using NUnit.Framework;
|
|||||||
namespace GFramework.Core.Tests.functional.pipe;
|
namespace GFramework.Core.Tests.functional.pipe;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// PipeExtensions扩展方法测试类,用于验证管道和函数组合扩展方法的正确性
|
/// PipeExtensions扩展方法测试类,用于验证管道和函数组合扩展方法的正确性
|
||||||
/// 包括管道操作、函数组合等核心功能的测试
|
/// 包括管道操作、函数组合等核心功能的测试
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[TestFixture]
|
[TestFixture]
|
||||||
public class PipeExtensionsTests
|
public class PipeExtensionsTests
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 测试Also方法 - 验证执行操作后返回原值功能
|
/// 测试Also方法 - 验证执行操作后返回原值功能
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Test]
|
[Test]
|
||||||
public void Also_Should_Execute_Action_And_Return_Original_Value()
|
public void Also_Should_Execute_Action_And_Return_Original_Value()
|
||||||
|
|||||||
@ -20,13 +20,13 @@ using GFramework.Core.coroutine.instructions;
|
|||||||
namespace GFramework.Core.coroutine.extensions;
|
namespace GFramework.Core.coroutine.extensions;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 命令协程扩展方法类
|
/// 命令协程扩展方法类
|
||||||
/// 提供将命令的异步执行包装为协程的功能
|
/// 提供将命令的异步执行包装为协程的功能
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static class CommandCoroutineExtensions
|
public static class CommandCoroutineExtensions
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 将 Command 的异步执行包装为协程,并处理异常
|
/// 将 Command 的异步执行包装为协程,并处理异常
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <typeparam name="TCommand">命令类型,必须实现 IAsyncCommand 接口</typeparam>
|
/// <typeparam name="TCommand">命令类型,必须实现 IAsyncCommand 接口</typeparam>
|
||||||
/// <param name="contextAware">上下文感知对象</param>
|
/// <param name="contextAware">上下文感知对象</param>
|
||||||
@ -43,14 +43,11 @@ public static class CommandCoroutineExtensions
|
|||||||
|
|
||||||
yield return task.AsCoroutineInstruction();
|
yield return task.AsCoroutineInstruction();
|
||||||
|
|
||||||
if (task.IsFaulted)
|
if (task.IsFaulted) onError?.Invoke(task.Exception!);
|
||||||
{
|
|
||||||
onError?.Invoke(task.Exception!);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 发送 Command 并等待指定 Event
|
/// 发送 Command 并等待指定 Event
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <typeparam name="TCommand">命令类型,必须实现 IAsyncCommand 接口</typeparam>
|
/// <typeparam name="TCommand">命令类型,必须实现 IAsyncCommand 接口</typeparam>
|
||||||
/// <typeparam name="TEvent">事件类型</typeparam>
|
/// <typeparam name="TEvent">事件类型</typeparam>
|
||||||
@ -89,10 +86,8 @@ public static class CommandCoroutineExtensions
|
|||||||
|
|
||||||
// 检查是否超时
|
// 检查是否超时
|
||||||
if (timeoutWait.IsTimeout)
|
if (timeoutWait.IsTimeout)
|
||||||
{
|
|
||||||
// 超时处理
|
// 超时处理
|
||||||
throw new TimeoutException($"wait for the event ${typeof(TEvent).Name} timeout.");
|
throw new TimeoutException($"wait for the event ${typeof(TEvent).Name} timeout.");
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -101,10 +96,7 @@ public static class CommandCoroutineExtensions
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 调用事件回调
|
// 调用事件回调
|
||||||
if (onEvent != null && wait.EventData != null)
|
if (onEvent != null && wait.EventData != null) onEvent.Invoke(wait.EventData);
|
||||||
{
|
|
||||||
onEvent.Invoke(wait.EventData);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
|
|||||||
@ -16,12 +16,12 @@ using GFramework.Core.Abstractions.coroutine;
|
|||||||
namespace GFramework.Core.coroutine.extensions;
|
namespace GFramework.Core.coroutine.extensions;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 提供协程组合扩展方法的静态类
|
/// 提供协程组合扩展方法的静态类
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static class CoroutineComposeExtensions
|
public static class CoroutineComposeExtensions
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 将一个协程枚举器与一个动作组合,先执行完第一个协程,然后执行指定的动作
|
/// 将一个协程枚举器与一个动作组合,先执行完第一个协程,然后执行指定的动作
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="first">第一个协程枚举器</param>
|
/// <param name="first">第一个协程枚举器</param>
|
||||||
/// <param name="next">在第一个协程完成后要执行的动作</param>
|
/// <param name="next">在第一个协程完成后要执行的动作</param>
|
||||||
@ -39,7 +39,7 @@ public static class CoroutineComposeExtensions
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 将两个协程枚举器顺序组合,先执行完第一个协程,再执行第二个协程
|
/// 将两个协程枚举器顺序组合,先执行完第一个协程,再执行第二个协程
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="first">第一个协程枚举器</param>
|
/// <param name="first">第一个协程枚举器</param>
|
||||||
/// <param name="second">第二个协程枚举器</param>
|
/// <param name="second">第二个协程枚举器</param>
|
||||||
|
|||||||
@ -18,13 +18,13 @@ using GFramework.Core.Abstractions.rule;
|
|||||||
namespace GFramework.Core.coroutine.extensions;
|
namespace GFramework.Core.coroutine.extensions;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查询协程扩展方法类
|
/// 查询协程扩展方法类
|
||||||
/// 提供将查询操作包装为协程的扩展方法
|
/// 提供将查询操作包装为协程的扩展方法
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static class QueryCoroutineExtensions
|
public static class QueryCoroutineExtensions
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 将 Query 包装为协程(立即返回结果)
|
/// 将 Query 包装为协程(立即返回结果)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <typeparam name="TQuery">查询类型,必须实现 IQuery<TResult> 接口</typeparam>
|
/// <typeparam name="TQuery">查询类型,必须实现 IQuery<TResult> 接口</typeparam>
|
||||||
/// <typeparam name="TResult">查询结果类型</typeparam>
|
/// <typeparam name="TResult">查询结果类型</typeparam>
|
||||||
|
|||||||
@ -20,7 +20,6 @@ public sealed class WaitForEvent<TEvent> : IYieldInstruction, IDisposable
|
|||||||
{
|
{
|
||||||
private bool _disposed;
|
private bool _disposed;
|
||||||
private volatile bool _done;
|
private volatile bool _done;
|
||||||
private TEvent? _eventData;
|
|
||||||
private IUnRegister? _unRegister;
|
private IUnRegister? _unRegister;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -38,7 +37,7 @@ public sealed class WaitForEvent<TEvent> : IYieldInstruction, IDisposable
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 获取接收到的事件数据
|
/// 获取接收到的事件数据
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public TEvent? EventData => _eventData;
|
public TEvent? EventData { get; private set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 释放资源
|
/// 释放资源
|
||||||
@ -77,7 +76,7 @@ public sealed class WaitForEvent<TEvent> : IYieldInstruction, IDisposable
|
|||||||
/// <param name="eventData">事件数据</param>
|
/// <param name="eventData">事件数据</param>
|
||||||
private void OnEventTriggered(TEvent eventData)
|
private void OnEventTriggered(TEvent eventData)
|
||||||
{
|
{
|
||||||
_eventData = eventData;
|
EventData = eventData;
|
||||||
_done = true;
|
_done = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -16,7 +16,7 @@ using GFramework.Core.Abstractions.coroutine;
|
|||||||
namespace GFramework.Core.coroutine.instructions;
|
namespace GFramework.Core.coroutine.instructions;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 带超时的事件等待指令
|
/// 带超时的事件等待指令
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <typeparam name="TEvent">事件类型</typeparam>
|
/// <typeparam name="TEvent">事件类型</typeparam>
|
||||||
/// <param name="waitForEvent">要包装的事件等待指令</param>
|
/// <param name="waitForEvent">要包装的事件等待指令</param>
|
||||||
@ -30,31 +30,28 @@ public sealed class WaitForEventWithTimeout<TEvent>(WaitForEvent<TEvent> waitFor
|
|||||||
private float _elapsedTime;
|
private float _elapsedTime;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 获取是否已超时
|
/// 获取是否已超时
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool IsTimeout => _elapsedTime >= timeout;
|
public bool IsTimeout => _elapsedTime >= timeout;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 获取接收到的事件数据
|
/// 获取接收到的事件数据
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public TEvent? EventData => _waitForEvent.EventData;
|
public TEvent? EventData => _waitForEvent.EventData;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 获取指令是否已完成(事件已触发或超时)
|
/// 获取指令是否已完成(事件已触发或超时)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool IsDone => _waitForEvent.IsDone || IsTimeout;
|
public bool IsDone => _waitForEvent.IsDone || IsTimeout;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 更新指令状态
|
/// 更新指令状态
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="deltaTime">时间增量</param>
|
/// <param name="deltaTime">时间增量</param>
|
||||||
public void Update(double deltaTime)
|
public void Update(double deltaTime)
|
||||||
{
|
{
|
||||||
// 只有在事件未完成时才累加经过的时间
|
// 只有在事件未完成时才累加经过的时间
|
||||||
if (!_waitForEvent.IsDone)
|
if (!_waitForEvent.IsDone) _elapsedTime += (float)deltaTime;
|
||||||
{
|
|
||||||
_elapsedTime += (float)deltaTime;
|
|
||||||
}
|
|
||||||
|
|
||||||
_waitForEvent.Update(deltaTime);
|
_waitForEvent.Update(deltaTime);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -16,17 +16,16 @@ using GFramework.Core.Abstractions.events;
|
|||||||
namespace GFramework.Core.events;
|
namespace GFramework.Core.events;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 事件监听器作用域,用于监听特定类型的事件并在触发时提供事件数据
|
/// 事件监听器作用域,用于监听特定类型的事件并在触发时提供事件数据
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <typeparam name="TEvent">要监听的事件类型</typeparam>
|
/// <typeparam name="TEvent">要监听的事件类型</typeparam>
|
||||||
public sealed class EventListenerScope<TEvent> : IDisposable
|
public sealed class EventListenerScope<TEvent> : IDisposable
|
||||||
{
|
{
|
||||||
private readonly IUnRegister? _unRegister;
|
private readonly IUnRegister? _unRegister;
|
||||||
private TEvent? _eventData;
|
|
||||||
private volatile bool _triggered;
|
private volatile bool _triggered;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 初始化事件监听器作用域的新实例
|
/// 初始化事件监听器作用域的新实例
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="eventBus">事件总线实例,用于注册事件监听器</param>
|
/// <param name="eventBus">事件总线实例,用于注册事件监听器</param>
|
||||||
public EventListenerScope(IEventBus eventBus)
|
public EventListenerScope(IEventBus eventBus)
|
||||||
@ -35,17 +34,17 @@ public sealed class EventListenerScope<TEvent> : IDisposable
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 获取接收到的事件数据
|
/// 获取接收到的事件数据
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public TEvent? EventData => _eventData;
|
public TEvent? EventData { get; private set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 获取事件是否已被触发
|
/// 获取事件是否已被触发
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool IsTriggered => _triggered;
|
public bool IsTriggered => _triggered;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 释放资源,取消事件监听器的注册
|
/// 释放资源,取消事件监听器的注册
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
@ -53,12 +52,12 @@ public sealed class EventListenerScope<TEvent> : IDisposable
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 事件触发时的回调方法,用于存储事件数据并标记已触发状态
|
/// 事件触发时的回调方法,用于存储事件数据并标记已触发状态
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="eventData">接收到的事件数据</param>
|
/// <param name="eventData">接收到的事件数据</param>
|
||||||
private void OnEventTriggered(TEvent eventData)
|
private void OnEventTriggered(TEvent eventData)
|
||||||
{
|
{
|
||||||
_eventData = eventData;
|
EventData = eventData;
|
||||||
_triggered = true;
|
_triggered = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -14,12 +14,12 @@
|
|||||||
namespace GFramework.Core.functional.control;
|
namespace GFramework.Core.functional.control;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 控制流扩展方法类,提供函数式编程风格的控制结构
|
/// 控制流扩展方法类,提供函数式编程风格的控制结构
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static class ControlExtensions
|
public static class ControlExtensions
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// TakeIf:条件返回值或null
|
/// TakeIf:条件返回值或null
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <typeparam name="TSource">输入值的类型</typeparam>
|
/// <typeparam name="TSource">输入值的类型</typeparam>
|
||||||
/// <param name="value">要进行条件判断的输入值</param>
|
/// <param name="value">要进行条件判断的输入值</param>
|
||||||
@ -29,10 +29,12 @@ public static class ControlExtensions
|
|||||||
this TSource value,
|
this TSource value,
|
||||||
Func<TSource, bool> predicate)
|
Func<TSource, bool> predicate)
|
||||||
where TSource : class
|
where TSource : class
|
||||||
=> predicate(value) ? value : null;
|
{
|
||||||
|
return predicate(value) ? value : null;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// TakeUnless:条件相反的TakeIf
|
/// TakeUnless:条件相反的TakeIf
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <typeparam name="TSource">输入值的类型</typeparam>
|
/// <typeparam name="TSource">输入值的类型</typeparam>
|
||||||
/// <param name="value">要进行条件判断的输入值</param>
|
/// <param name="value">要进行条件判断的输入值</param>
|
||||||
@ -42,5 +44,7 @@ public static class ControlExtensions
|
|||||||
this TSource value,
|
this TSource value,
|
||||||
Func<TSource, bool> predicate)
|
Func<TSource, bool> predicate)
|
||||||
where TSource : class
|
where TSource : class
|
||||||
=> !predicate(value) ? value : null;
|
{
|
||||||
|
return !predicate(value) ? value : null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@ -16,17 +16,17 @@ using System.Collections.Concurrent;
|
|||||||
namespace GFramework.Core.functional.functions;
|
namespace GFramework.Core.functional.functions;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 函数式编程扩展方法集合,提供柯里化、偏函数应用、重复执行、安全执行和缓存等功能
|
/// 函数式编程扩展方法集合,提供柯里化、偏函数应用、重复执行、安全执行和缓存等功能
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static class FunctionExtensions
|
public static class FunctionExtensions
|
||||||
{
|
{
|
||||||
#region Repeat
|
#region Repeat
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Repeat:对值重复应用函数 n 次
|
/// Repeat:对值重复应用函数 n 次
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <exception cref="ArgumentOutOfRangeException">
|
/// <exception cref="ArgumentOutOfRangeException">
|
||||||
/// 当 times 小于 0 时抛出
|
/// 当 times 小于 0 时抛出
|
||||||
/// </exception>
|
/// </exception>
|
||||||
public static T Repeat<T>(
|
public static T Repeat<T>(
|
||||||
this T value,
|
this T value,
|
||||||
@ -36,10 +36,7 @@ public static class FunctionExtensions
|
|||||||
ArgumentOutOfRangeException.ThrowIfNegative(times);
|
ArgumentOutOfRangeException.ThrowIfNegative(times);
|
||||||
|
|
||||||
var result = value;
|
var result = value;
|
||||||
for (var i = 0; i < times; i++)
|
for (var i = 0; i < times; i++) result = func(result);
|
||||||
{
|
|
||||||
result = func(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@ -49,7 +46,7 @@ public static class FunctionExtensions
|
|||||||
#region Try → Result
|
#region Try → Result
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Try:安全执行并返回 language-ext 的 Result
|
/// Try:安全执行并返回 language-ext 的 Result
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static Result<TResult> Try<TSource, TResult>(
|
public static Result<TResult> Try<TSource, TResult>(
|
||||||
this TSource value,
|
this TSource value,
|
||||||
@ -70,13 +67,12 @@ public static class FunctionExtensions
|
|||||||
#region Memoize (Unbounded / Unsafe)
|
#region Memoize (Unbounded / Unsafe)
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// MemoizeUnbounded:
|
/// MemoizeUnbounded:
|
||||||
/// 对函数结果进行无界缓存(线程安全)
|
/// 对函数结果进行无界缓存(线程安全)
|
||||||
///
|
/// ⚠ 注意:
|
||||||
/// ⚠ 注意:
|
/// - 缓存永不释放
|
||||||
/// - 缓存永不释放
|
/// - TSource 必须具有稳定的 Equals / GetHashCode
|
||||||
/// - TSource 必须具有稳定的 Equals / GetHashCode
|
/// - 仅适用于纯函数
|
||||||
/// - 仅适用于纯函数
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static Func<TSource, TResult> MemoizeUnbounded<TSource, TResult>(
|
public static Func<TSource, TResult> MemoizeUnbounded<TSource, TResult>(
|
||||||
this Func<TSource, TResult> func)
|
this Func<TSource, TResult> func)
|
||||||
@ -91,14 +87,15 @@ public static class FunctionExtensions
|
|||||||
#region Partial (Advanced)
|
#region Partial (Advanced)
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Partial:部分应用(二参数函数固定第一个参数)
|
/// Partial:部分应用(二参数函数固定第一个参数)
|
||||||
///
|
/// ⚠ 偏函数应用属于高级用法,不建议在业务代码滥用
|
||||||
/// ⚠ 偏函数应用属于高级用法,不建议在业务代码滥用
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static Func<T2, TResult> Partial<T1, T2, TResult>(
|
public static Func<T2, TResult> Partial<T1, T2, TResult>(
|
||||||
this Func<T1, T2, TResult> func,
|
this Func<T1, T2, TResult> func,
|
||||||
T1 firstArg)
|
T1 firstArg)
|
||||||
=> second => func(firstArg, second);
|
{
|
||||||
|
return second => func(firstArg, second);
|
||||||
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
@ -14,15 +14,14 @@
|
|||||||
namespace GFramework.Core.functional.pipe;
|
namespace GFramework.Core.functional.pipe;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 提供函数式编程中的管道和组合操作扩展方法
|
/// 提供函数式编程中的管道和组合操作扩展方法
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static class PipeExtensions
|
public static class PipeExtensions
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Also:
|
/// Also:
|
||||||
/// 对值执行副作用操作并返回原值
|
/// 对值执行副作用操作并返回原值
|
||||||
///
|
/// 适用于日志、调试、状态同步等场景
|
||||||
/// 适用于日志、调试、状态同步等场景
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static T Also<T>(
|
public static T Also<T>(
|
||||||
this T value,
|
this T value,
|
||||||
|
|||||||
@ -16,27 +16,27 @@ using GFramework.Game.Abstractions.enums;
|
|||||||
namespace GFramework.Game.Abstractions.data;
|
namespace GFramework.Game.Abstractions.data;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 数据位置接口,定义了数据存储的位置信息和相关属性
|
/// 数据位置接口,定义了数据存储的位置信息和相关属性
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public interface IDataLocation
|
public interface IDataLocation
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 存储键(文件路径 / redis key / db key)
|
/// 存储键(文件路径 / redis key / db key)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
string Key { get; }
|
string Key { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 存储类型(Local / Remote / Database / Memory)
|
/// 存储类型(Local / Remote / Database / Memory)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
StorageKind Kind { get; }
|
StorageKinds Kinds { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 命名空间/分区
|
/// 命名空间/分区
|
||||||
/// </summary>
|
/// </summary>
|
||||||
string? Namespace { get; }
|
string? Namespace { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 扩展元数据(用于存储额外信息,如压缩、加密等)
|
/// 扩展元数据(用于存储额外信息,如压缩、加密等)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
IReadOnlyDictionary<string, string>? Metadata { get; }
|
IReadOnlyDictionary<string, string>? Metadata { get; }
|
||||||
}
|
}
|
||||||
@ -16,14 +16,14 @@ using GFramework.Core.Abstractions.utility;
|
|||||||
namespace GFramework.Game.Abstractions.data;
|
namespace GFramework.Game.Abstractions.data;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 定义数据位置提供者的接口,用于获取指定类型的数据位置信息
|
/// 定义数据位置提供者的接口,用于获取指定类型的数据位置信息
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public interface IDataLocationProvider:IUtility
|
public interface IDataLocationProvider : IUtility
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 获取指定类型的数据位置
|
/// 获取指定类型的数据位置
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="type">需要获取位置信息的类型</param>
|
/// <param name="type">需要获取位置信息的类型</param>
|
||||||
/// <returns>与指定类型关联的数据位置对象</returns>
|
/// <returns>与指定类型关联的数据位置对象</returns>
|
||||||
IDataLocation GetLocation(Type type);
|
IDataLocation GetLocation(Type type);
|
||||||
}
|
}
|
||||||
@ -21,7 +21,7 @@ namespace GFramework.Game.Abstractions.data;
|
|||||||
public interface IDataRepository : IUtility
|
public interface IDataRepository : IUtility
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 异步加载指定位置的数据
|
/// 异步加载指定位置的数据
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <typeparam name="T">要加载的数据类型,必须实现IData接口并具有无参构造函数</typeparam>
|
/// <typeparam name="T">要加载的数据类型,必须实现IData接口并具有无参构造函数</typeparam>
|
||||||
/// <param name="location">数据位置信息</param>
|
/// <param name="location">数据位置信息</param>
|
||||||
@ -31,7 +31,7 @@ public interface IDataRepository : IUtility
|
|||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 异步保存数据到指定位置
|
/// 异步保存数据到指定位置
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <typeparam name="T">要保存的数据类型,必须实现IData接口</typeparam>
|
/// <typeparam name="T">要保存的数据类型,必须实现IData接口</typeparam>
|
||||||
/// <param name="location">数据位置信息</param>
|
/// <param name="location">数据位置信息</param>
|
||||||
@ -41,21 +41,21 @@ public interface IDataRepository : IUtility
|
|||||||
where T : class, IData;
|
where T : class, IData;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 异步检查指定位置是否存在数据
|
/// 异步检查指定位置是否存在数据
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="location">数据位置信息</param>
|
/// <param name="location">数据位置信息</param>
|
||||||
/// <returns>返回布尔值,表示数据是否存在</returns>
|
/// <returns>返回布尔值,表示数据是否存在</returns>
|
||||||
Task<bool> ExistsAsync(IDataLocation location);
|
Task<bool> ExistsAsync(IDataLocation location);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 异步删除指定位置的数据
|
/// 异步删除指定位置的数据
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="location">数据位置信息</param>
|
/// <param name="location">数据位置信息</param>
|
||||||
/// <returns>返回异步操作任务</returns>
|
/// <returns>返回异步操作任务</returns>
|
||||||
Task DeleteAsync(IDataLocation location);
|
Task DeleteAsync(IDataLocation location);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 异步批量保存多个数据项到各自的位置
|
/// 异步批量保存多个数据项到各自的位置
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="dataList">包含数据位置和对应数据对象的可枚举集合</param>
|
/// <param name="dataList">包含数据位置和对应数据对象的可枚举集合</param>
|
||||||
/// <returns>返回异步操作任务</returns>
|
/// <returns>返回异步操作任务</returns>
|
||||||
|
|||||||
@ -14,21 +14,21 @@
|
|||||||
namespace GFramework.Game.Abstractions.data;
|
namespace GFramework.Game.Abstractions.data;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 定义设置数据仓库接口,用于管理应用程序设置数据的存储和检索
|
/// 定义设置数据仓库接口,用于管理应用程序设置数据的存储和检索
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <remarks>
|
/// <remarks>
|
||||||
/// 该接口继承自IDataRepository,专门用于处理配置设置相关的数据操作
|
/// 该接口继承自IDataRepository,专门用于处理配置设置相关的数据操作
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
public interface ISettingsDataRepository : IDataRepository
|
public interface ISettingsDataRepository : IDataRepository
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 异步加载所有设置项
|
/// 异步加载所有设置项
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>
|
/// <returns>
|
||||||
/// 返回一个包含所有设置键值对的字典,其中键为设置名称,值为对应的设置数据对象
|
/// 返回一个包含所有设置键值对的字典,其中键为设置名称,值为对应的设置数据对象
|
||||||
/// </returns>
|
/// </returns>
|
||||||
/// <remarks>
|
/// <remarks>
|
||||||
/// 此方法将从数据源中异步读取所有可用的设置项,并将其组织成字典格式返回
|
/// 此方法将从数据源中异步读取所有可用的设置项,并将其组织成字典格式返回
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
Task<IDictionary<string, IData>> LoadAllAsync();
|
Task<IDictionary<string, IData>> LoadAllAsync();
|
||||||
|
|
||||||
|
|||||||
@ -10,23 +10,24 @@
|
|||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
namespace GFramework.Game.Abstractions.data;
|
namespace GFramework.Game.Abstractions.data;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 版本化数据接口,继承自IData接口
|
/// 版本化数据接口,继承自IData接口
|
||||||
/// 提供版本控制和修改时间跟踪功能
|
/// 提供版本控制和修改时间跟踪功能
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public interface IVersionedData : IData
|
public interface IVersionedData : IData
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 获取数据的版本号
|
/// 获取数据的版本号
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>当前数据的版本号,用于标识数据的版本状态</returns>
|
/// <returns>当前数据的版本号,用于标识数据的版本状态</returns>
|
||||||
int Version { get; }
|
int Version { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 获取数据最后修改的时间
|
/// 获取数据最后修改的时间
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>DateTime类型的最后修改时间戳</returns>
|
/// <returns>DateTime类型的最后修改时间戳</returns>
|
||||||
DateTime LastModified { get; }
|
DateTime LastModified { get; }
|
||||||
}
|
}
|
||||||
@ -17,5 +17,4 @@ namespace GFramework.Game.Abstractions.data.events;
|
|||||||
/// 表示数据删除事件的记录类型
|
/// 表示数据删除事件的记录类型
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="Location">数据位置信息,标识被删除数据的位置</param>
|
/// <param name="Location">数据位置信息,标识被删除数据的位置</param>
|
||||||
public sealed record DataDeletedEvent(IDataLocation Location);
|
public sealed record DataDeletedEvent(IDataLocation Location);
|
||||||
|
|
||||||
@ -14,34 +14,34 @@
|
|||||||
namespace GFramework.Game.Abstractions.enums;
|
namespace GFramework.Game.Abstractions.enums;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 存储类型枚举,用于标识不同的存储方式
|
/// 存储类型枚举,用于标识不同的存储方式
|
||||||
/// 此枚举使用 Flags 特性,支持位运算组合多个存储类型
|
/// 此枚举使用 Flags 特性,支持位运算组合多个存储类型
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Flags]
|
[Flags]
|
||||||
public enum StorageKind
|
public enum StorageKinds
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 无存储类型
|
/// 无存储类型
|
||||||
/// </summary>
|
/// </summary>
|
||||||
None = 0,
|
None = 0,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 本地文件系统存储
|
/// 本地文件系统存储
|
||||||
/// </summary>
|
/// </summary>
|
||||||
Local = 1 << 0,
|
Local = 1 << 0,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 内存存储
|
/// 内存存储
|
||||||
/// </summary>
|
/// </summary>
|
||||||
Memory = 1 << 1,
|
Memory = 1 << 1,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 远程存储
|
/// 远程存储
|
||||||
/// </summary>
|
/// </summary>
|
||||||
Remote = 1 << 2,
|
Remote = 1 << 2,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 数据库存储
|
/// 数据库存储
|
||||||
/// </summary>
|
/// </summary>
|
||||||
Database = 1 << 3,
|
Database = 1 << 3
|
||||||
}
|
}
|
||||||
@ -14,19 +14,19 @@
|
|||||||
namespace GFramework.Game.Abstractions.setting;
|
namespace GFramework.Game.Abstractions.setting;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 定义一个可重置且可应用设置的接口
|
/// 定义一个可重置且可应用设置的接口
|
||||||
/// 该接口继承自IResettable和IApplyAbleSettings接口,组合了重置功能和应用设置功能
|
/// 该接口继承自IResettable和IApplyAbleSettings接口,组合了重置功能和应用设置功能
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public interface IResetApplyAbleSettings : IResettable, IApplyAbleSettings
|
public interface IResetApplyAbleSettings : IResettable, IApplyAbleSettings
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 获取设置数据对象
|
/// 获取设置数据对象
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>ISettingsData类型的设置数据</returns>
|
/// <returns>ISettingsData类型的设置数据</returns>
|
||||||
ISettingsData Data { get; }
|
ISettingsData Data { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 获取数据类型信息
|
/// 获取数据类型信息
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>表示数据类型的Type对象</returns>
|
/// <returns>表示数据类型的Type对象</returns>
|
||||||
Type DataType { get; }
|
Type DataType { get; }
|
||||||
|
|||||||
@ -17,7 +17,7 @@ using GFramework.Game.Abstractions.data;
|
|||||||
namespace GFramework.Game.Abstractions.setting;
|
namespace GFramework.Game.Abstractions.setting;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 定义游戏设置数据的接口
|
/// 定义游戏设置数据的接口
|
||||||
/// 该接口继承自IData和IResettable接口,提供数据管理和重置功能
|
/// 该接口继承自IData和IResettable接口,提供数据管理和重置功能
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public interface ISettingsData : IResettable, IVersionedData, ILoadableFrom<ISettingsData>;
|
public interface ISettingsData : IResettable, IVersionedData, ILoadableFrom<ISettingsData>;
|
||||||
@ -3,10 +3,10 @@
|
|||||||
namespace GFramework.Game.Abstractions.setting;
|
namespace GFramework.Game.Abstractions.setting;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 设置模型接口:
|
/// 设置模型接口:
|
||||||
/// - 管理 Settings Data 的生命周期
|
/// - 管理 Settings Data 的生命周期
|
||||||
/// - 管理并编排 Settings Applicator
|
/// - 管理并编排 Settings Applicator
|
||||||
/// - 管理 Settings Migration
|
/// - 管理 Settings Migration
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public interface ISettingsModel : IModel
|
public interface ISettingsModel : IModel
|
||||||
{
|
{
|
||||||
@ -15,14 +15,14 @@ public interface ISettingsModel : IModel
|
|||||||
// =========================
|
// =========================
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 获取指定类型的设置数据(唯一实例)
|
/// 获取指定类型的设置数据(唯一实例)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <typeparam name="T">设置数据类型,必须继承自ISettingsData并具有无参构造函数</typeparam>
|
/// <typeparam name="T">设置数据类型,必须继承自ISettingsData并具有无参构造函数</typeparam>
|
||||||
/// <returns>指定类型的设置数据实例</returns>
|
/// <returns>指定类型的设置数据实例</returns>
|
||||||
T GetData<T>() where T : class, ISettingsData, new();
|
T GetData<T>() where T : class, ISettingsData, new();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 获取所有已创建的设置数据
|
/// 获取所有已创建的设置数据
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>所有已创建的设置数据集合</returns>
|
/// <returns>所有已创建的设置数据集合</returns>
|
||||||
IEnumerable<ISettingsData> AllData();
|
IEnumerable<ISettingsData> AllData();
|
||||||
@ -33,7 +33,7 @@ public interface ISettingsModel : IModel
|
|||||||
// =========================
|
// =========================
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 注册设置应用器
|
/// 注册设置应用器
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <typeparam name="T">设置数据类型,必须实现IResetApplyAbleSettings接口且具有无参构造函数</typeparam>
|
/// <typeparam name="T">设置数据类型,必须实现IResetApplyAbleSettings接口且具有无参构造函数</typeparam>
|
||||||
/// <param name="applicator">要注册的设置应用器</param>
|
/// <param name="applicator">要注册的设置应用器</param>
|
||||||
@ -42,7 +42,7 @@ public interface ISettingsModel : IModel
|
|||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 获取指定类型的设置应用器
|
/// 获取指定类型的设置应用器
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <typeparam name="T">要获取的设置应用器类型,必须继承自IResetApplyAbleSettings</typeparam>
|
/// <typeparam name="T">要获取的设置应用器类型,必须继承自IResetApplyAbleSettings</typeparam>
|
||||||
/// <returns>设置应用器实例,如果不存在则返回null</returns>
|
/// <returns>设置应用器实例,如果不存在则返回null</returns>
|
||||||
@ -50,7 +50,7 @@ public interface ISettingsModel : IModel
|
|||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 获取所有设置应用器
|
/// 获取所有设置应用器
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>所有设置应用器的集合</returns>
|
/// <returns>所有设置应用器的集合</returns>
|
||||||
IEnumerable<IResetApplyAbleSettings> AllApplicators();
|
IEnumerable<IResetApplyAbleSettings> AllApplicators();
|
||||||
@ -61,7 +61,7 @@ public interface ISettingsModel : IModel
|
|||||||
// =========================
|
// =========================
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 注册设置迁移器
|
/// 注册设置迁移器
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="migration">要注册的设置迁移器</param>
|
/// <param name="migration">要注册的设置迁移器</param>
|
||||||
/// <returns>当前设置模型实例,支持链式调用</returns>
|
/// <returns>当前设置模型实例,支持链式调用</returns>
|
||||||
@ -73,19 +73,19 @@ public interface ISettingsModel : IModel
|
|||||||
// =========================
|
// =========================
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 初始化所有设置数据(加载 + 迁移)
|
/// 初始化所有设置数据(加载 + 迁移)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>异步操作任务</returns>
|
/// <returns>异步操作任务</returns>
|
||||||
Task InitializeAsync();
|
Task InitializeAsync();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 保存所有设置数据
|
/// 保存所有设置数据
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>异步操作任务</returns>
|
/// <returns>异步操作任务</returns>
|
||||||
Task SaveAllAsync();
|
Task SaveAllAsync();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 应用所有设置
|
/// 应用所有设置
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>异步操作任务</returns>
|
/// <returns>异步操作任务</returns>
|
||||||
Task ApplyAllAsync();
|
Task ApplyAllAsync();
|
||||||
@ -98,7 +98,7 @@ public interface ISettingsModel : IModel
|
|||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 重置所有设置数据与应用器
|
/// 重置所有设置数据与应用器
|
||||||
/// </summary>
|
/// </summary>
|
||||||
void ResetAll();
|
void ResetAll();
|
||||||
}
|
}
|
||||||
@ -48,10 +48,7 @@ public class AudioSettings : ISettingsData
|
|||||||
public void LoadFrom(ISettingsData source)
|
public void LoadFrom(ISettingsData source)
|
||||||
{
|
{
|
||||||
// 检查数据源是否为音频设置类型
|
// 检查数据源是否为音频设置类型
|
||||||
if (source is not AudioSettings audioSettings)
|
if (source is not AudioSettings audioSettings) return;
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 将源数据中的各个音量设置复制到当前对象
|
// 将源数据中的各个音量设置复制到当前对象
|
||||||
MasterVolume = audioSettings.MasterVolume;
|
MasterVolume = audioSettings.MasterVolume;
|
||||||
|
|||||||
@ -47,10 +47,7 @@ public class GraphicsSettings : ISettingsData
|
|||||||
public void LoadFrom(ISettingsData source)
|
public void LoadFrom(ISettingsData source)
|
||||||
{
|
{
|
||||||
// 检查源数据是否为GraphicsSettings类型,如果不是则直接返回
|
// 检查源数据是否为GraphicsSettings类型,如果不是则直接返回
|
||||||
if (source is not GraphicsSettings settings)
|
if (source is not GraphicsSettings settings) return;
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 将源设置中的属性值复制到当前对象
|
// 将源设置中的属性值复制到当前对象
|
||||||
Fullscreen = settings.Fullscreen;
|
Fullscreen = settings.Fullscreen;
|
||||||
|
|||||||
@ -54,10 +54,7 @@ public class LocalizationSettings : ISettingsData
|
|||||||
/// </remarks>
|
/// </remarks>
|
||||||
public void LoadFrom(ISettingsData source)
|
public void LoadFrom(ISettingsData source)
|
||||||
{
|
{
|
||||||
if (source is not LocalizationSettings settings)
|
if (source is not LocalizationSettings settings) return;
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Language = settings.Language;
|
Language = settings.Language;
|
||||||
Version = settings.Version;
|
Version = settings.Version;
|
||||||
|
|||||||
@ -35,13 +35,8 @@ public class DataRepository(IStorage? storage, DataRepositoryOptions? options =
|
|||||||
throw new InvalidOperationException(
|
throw new InvalidOperationException(
|
||||||
"Failed to initialize storage. No IStorage utility found in context.");
|
"Failed to initialize storage. No IStorage utility found in context.");
|
||||||
|
|
||||||
protected override void OnInit()
|
|
||||||
{
|
|
||||||
_storage ??= this.GetUtility<IStorage>()!;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 异步加载指定位置的数据
|
/// 异步加载指定位置的数据
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <typeparam name="T">数据类型,必须实现IData接口</typeparam>
|
/// <typeparam name="T">数据类型,必须实现IData接口</typeparam>
|
||||||
/// <param name="location">数据位置信息</param>
|
/// <param name="location">数据位置信息</param>
|
||||||
@ -66,7 +61,7 @@ public class DataRepository(IStorage? storage, DataRepositoryOptions? options =
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 异步保存数据到指定位置
|
/// 异步保存数据到指定位置
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <typeparam name="T">数据类型,必须实现IData接口</typeparam>
|
/// <typeparam name="T">数据类型,必须实现IData接口</typeparam>
|
||||||
/// <param name="location">数据位置信息</param>
|
/// <param name="location">数据位置信息</param>
|
||||||
@ -91,15 +86,17 @@ public class DataRepository(IStorage? storage, DataRepositoryOptions? options =
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 检查指定位置的数据是否存在
|
/// 检查指定位置的数据是否存在
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="location">数据位置信息</param>
|
/// <param name="location">数据位置信息</param>
|
||||||
/// <returns>如果数据存在返回true,否则返回false</returns>
|
/// <returns>如果数据存在返回true,否则返回false</returns>
|
||||||
public Task<bool> ExistsAsync(IDataLocation location)
|
public Task<bool> ExistsAsync(IDataLocation location)
|
||||||
=> Storage.ExistsAsync(location.ToStorageKey());
|
{
|
||||||
|
return Storage.ExistsAsync(location.ToStorageKey());
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 异步删除指定位置的数据
|
/// 异步删除指定位置的数据
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="location">数据位置信息</param>
|
/// <param name="location">数据位置信息</param>
|
||||||
public async Task DeleteAsync(IDataLocation location)
|
public async Task DeleteAsync(IDataLocation location)
|
||||||
@ -111,18 +108,20 @@ public class DataRepository(IStorage? storage, DataRepositoryOptions? options =
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 异步批量保存多个数据项
|
/// 异步批量保存多个数据项
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="dataList">包含数据位置和数据对象的枚举集合</param>
|
/// <param name="dataList">包含数据位置和数据对象的枚举集合</param>
|
||||||
public async Task SaveAllAsync(IEnumerable<(IDataLocation location, IData data)> dataList)
|
public async Task SaveAllAsync(IEnumerable<(IDataLocation location, IData data)> dataList)
|
||||||
{
|
{
|
||||||
var valueTuples = dataList.ToList();
|
var valueTuples = dataList.ToList();
|
||||||
foreach (var (location, data) in valueTuples)
|
foreach (var (location, data) in valueTuples) await SaveAsync(location, data);
|
||||||
{
|
|
||||||
await SaveAsync(location, data);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_options.EnableEvents)
|
if (_options.EnableEvents)
|
||||||
this.SendEvent(new DataBatchSavedEvent(valueTuples));
|
this.SendEvent(new DataBatchSavedEvent(valueTuples));
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
protected override void OnInit()
|
||||||
|
{
|
||||||
|
_storage ??= this.GetUtility<IStorage>()!;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -209,13 +209,9 @@ public class UnifiedSettingsDataRepository(
|
|||||||
var key = UnifiedKey;
|
var key = UnifiedKey;
|
||||||
|
|
||||||
if (await Storage.ExistsAsync(key))
|
if (await Storage.ExistsAsync(key))
|
||||||
{
|
|
||||||
_file = await Storage.ReadAsync<UnifiedSettingsFile>(key);
|
_file = await Storage.ReadAsync<UnifiedSettingsFile>(key);
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
|
||||||
_file = new UnifiedSettingsFile { Version = 1 };
|
_file = new UnifiedSettingsFile { Version = 1 };
|
||||||
}
|
|
||||||
|
|
||||||
_loaded = true;
|
_loaded = true;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -16,19 +16,19 @@ using GFramework.Core.Abstractions.versioning;
|
|||||||
namespace GFramework.Game.data;
|
namespace GFramework.Game.data;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 统一设置文件类,用于管理应用程序的配置设置
|
/// 统一设置文件类,用于管理应用程序的配置设置
|
||||||
/// 实现了版本控制接口,支持配置文件的版本管理
|
/// 实现了版本控制接口,支持配置文件的版本管理
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal sealed class UnifiedSettingsFile:IVersioned
|
internal sealed class UnifiedSettingsFile : IVersioned
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 配置节集合,存储不同类型的配置数据
|
/// 配置节集合,存储不同类型的配置数据
|
||||||
/// 键为配置节名称,值为配置对象
|
/// 键为配置节名称,值为配置对象
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Dictionary<string, string> Sections { get; set; } = new();
|
public Dictionary<string, string> Sections { get; set; } = new();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 配置文件版本号,用于版本控制和兼容性检查
|
/// 配置文件版本号,用于版本控制和兼容性检查
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public int Version { get; set; }
|
public int Version { get; set; }
|
||||||
}
|
}
|
||||||
@ -16,12 +16,12 @@ using GFramework.Game.Abstractions.data;
|
|||||||
namespace GFramework.Game.extensions;
|
namespace GFramework.Game.extensions;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 提供数据位置相关的扩展方法
|
/// 提供数据位置相关的扩展方法
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static class DataLocationExtensions
|
public static class DataLocationExtensions
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 将数据位置转换为存储键
|
/// 将数据位置转换为存储键
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="location">数据位置对象</param>
|
/// <param name="location">数据位置对象</param>
|
||||||
/// <returns>格式化的存储键字符串,如果命名空间为空则返回键值,否则返回"命名空间/键值"格式</returns>
|
/// <returns>格式化的存储键字符串,如果命名空间为空则返回键值,否则返回"命名空间/键值"格式</returns>
|
||||||
@ -29,4 +29,4 @@ public static class DataLocationExtensions
|
|||||||
{
|
{
|
||||||
return string.IsNullOrEmpty(location.Namespace) ? location.Key : $"{location.Namespace}/{location.Key}";
|
return string.IsNullOrEmpty(location.Namespace) ? location.Key : $"{location.Namespace}/{location.Key}";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -114,7 +114,6 @@ public class SettingsModel<TRepository>(IDataLocationProvider? locationProvider,
|
|||||||
}
|
}
|
||||||
|
|
||||||
foreach (var data in _data.Values)
|
foreach (var data in _data.Values)
|
||||||
{
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var type = data.GetType();
|
var type = data.GetType();
|
||||||
@ -135,7 +134,6 @@ public class SettingsModel<TRepository>(IDataLocationProvider? locationProvider,
|
|||||||
{
|
{
|
||||||
Log.Error($"Failed to initialize settings data: {data.GetType().Name}", ex);
|
Log.Error($"Failed to initialize settings data: {data.GetType().Name}", ex);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
this.SendEvent(new SettingsInitializedEvent());
|
this.SendEvent(new SettingsInitializedEvent());
|
||||||
}
|
}
|
||||||
@ -147,7 +145,6 @@ public class SettingsModel<TRepository>(IDataLocationProvider? locationProvider,
|
|||||||
public async Task SaveAllAsync()
|
public async Task SaveAllAsync()
|
||||||
{
|
{
|
||||||
foreach (var data in _data.Values)
|
foreach (var data in _data.Values)
|
||||||
{
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var location = LocationProvider.GetLocation(data.GetType());
|
var location = LocationProvider.GetLocation(data.GetType());
|
||||||
@ -157,7 +154,6 @@ public class SettingsModel<TRepository>(IDataLocationProvider? locationProvider,
|
|||||||
{
|
{
|
||||||
Log.Error($"Failed to save settings data: {data.GetType().Name}", ex);
|
Log.Error($"Failed to save settings data: {data.GetType().Name}", ex);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
this.SendEvent(new SettingsSavedAllEvent());
|
this.SendEvent(new SettingsSavedAllEvent());
|
||||||
}
|
}
|
||||||
@ -168,7 +164,6 @@ public class SettingsModel<TRepository>(IDataLocationProvider? locationProvider,
|
|||||||
public async Task ApplyAllAsync()
|
public async Task ApplyAllAsync()
|
||||||
{
|
{
|
||||||
foreach (var applicator in _applicators)
|
foreach (var applicator in _applicators)
|
||||||
{
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await applicator.Value.Apply();
|
await applicator.Value.Apply();
|
||||||
@ -177,7 +172,6 @@ public class SettingsModel<TRepository>(IDataLocationProvider? locationProvider,
|
|||||||
{
|
{
|
||||||
Log.Error($"Failed to apply settings: {applicator.GetType().Name}", ex);
|
Log.Error($"Failed to apply settings: {applicator.GetType().Name}", ex);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
this.SendEvent(new SettingsAppliedAllEvent());
|
this.SendEvent(new SettingsAppliedAllEvent());
|
||||||
}
|
}
|
||||||
@ -207,7 +201,7 @@ public class SettingsModel<TRepository>(IDataLocationProvider? locationProvider,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 获取指定类型的设置应用器
|
/// 获取指定类型的设置应用器
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <typeparam name="T">要获取的设置应用器类型,必须继承自IResetApplyAbleSettings</typeparam>
|
/// <typeparam name="T">要获取的设置应用器类型,必须继承自IResetApplyAbleSettings</typeparam>
|
||||||
/// <returns>设置应用器实例,如果不存在则返回null</returns>
|
/// <returns>设置应用器实例,如果不存在则返回null</returns>
|
||||||
|
|||||||
@ -1,5 +1,4 @@
|
|||||||
using System.Collections.Concurrent;
|
using System.IO;
|
||||||
using System.IO;
|
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using GFramework.Core.Abstractions.serializer;
|
using GFramework.Core.Abstractions.serializer;
|
||||||
using GFramework.Game.Abstractions.storage;
|
using GFramework.Game.Abstractions.storage;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user