feat(godot): 添加Godot UI注册表和日志测试用例

- 实现GodotUiRegistry类用于管理PackedScene类型的UI资源注册和获取
- 添加完整的控制台日志记录器单元测试覆盖所有日志级别和功能
- 添加日志工厂相关测试用例验证不同配置下的日志行为
- 实现基础日志抽象类的完整测试覆盖各种日志记录场景
This commit is contained in:
GeWuYou 2026-01-15 20:51:06 +08:00
parent 5d11666fd8
commit d1b4ef1971
4 changed files with 778 additions and 0 deletions

View File

@ -0,0 +1,203 @@
using GFramework.Core.Abstractions.logging;
using GFramework.Core.logging;
using NUnit.Framework;
namespace GFramework.Core.Tests.logging;
[TestFixture]
public class ConsoleLoggerTests
{
[SetUp]
public void SetUp()
{
_stringWriter = new StringWriter();
_logger = new ConsoleLogger("TestLogger", LogLevel.Info, _stringWriter, false);
}
[TearDown]
public void TearDown()
{
_stringWriter?.Dispose();
}
private StringWriter _stringWriter = null!;
private ConsoleLogger _logger = null!;
[Test]
public void Constructor_WithDefaultName_ShouldUseRootLoggerName()
{
var defaultLogger = new ConsoleLogger();
Assert.That(defaultLogger.Name(), Is.EqualTo("ROOT"));
}
[Test]
public void Constructor_WithCustomName_ShouldUseCustomName()
{
var customLogger = new ConsoleLogger("CustomLogger");
Assert.That(customLogger.Name(), Is.EqualTo("CustomLogger"));
}
[Test]
public void Constructor_WithCustomMinLevel_ShouldRespectMinLevel()
{
var debugLogger = new ConsoleLogger(null, LogLevel.Debug, _stringWriter, false);
debugLogger.Debug("Debug message");
debugLogger.Trace("Trace message");
var output = _stringWriter.ToString();
Assert.That(output, Does.Contain("DEBUG"));
Assert.That(output, Does.Not.Contain("TRACE"));
}
[Test]
public void Constructor_WithCustomWriter_ShouldWriteToCustomWriter()
{
_logger.Info("Test message");
var output = _stringWriter.ToString();
Assert.That(output, Does.Contain("Test message"));
}
[Test]
public void Write_ShouldIncludeTimestamp()
{
_logger.Info("Test message");
var output = _stringWriter.ToString();
Assert.That(output, Does.Match(@"\[\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}\.\d{3}\]"));
}
[Test]
public void Write_ShouldIncludeLevel()
{
_logger.Info("Test message");
var output = _stringWriter.ToString();
Assert.That(output, Does.Contain("INFO"));
_stringWriter.GetStringBuilder().Clear();
_logger.Error("Error message");
output = _stringWriter.ToString();
Assert.That(output, Does.Contain("ERROR"));
}
[Test]
public void Write_ShouldIncludeLoggerName()
{
_logger.Info("Test message");
var output = _stringWriter.ToString();
Assert.That(output, Does.Contain("[TestLogger]"));
}
[Test]
public void Write_WithException_ShouldIncludeException()
{
var exception = new Exception("Test exception");
_logger.Error("Error message", exception);
var output = _stringWriter.ToString();
Assert.That(output, Does.Contain("Error message"));
Assert.That(output, Does.Contain("Test exception"));
}
[Test]
public void Write_WithMultipleLines_ShouldFormatCorrectly()
{
_logger.Info("Line 1");
_logger.Warn("Line 2");
_logger.Error("Line 3");
var output = _stringWriter.ToString();
var lines = output.Split(new[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries);
Assert.That(lines.Length, Is.EqualTo(3));
Assert.That(lines[0], Does.Contain("INFO"));
Assert.That(lines[1], Does.Contain("WARN"));
Assert.That(lines[2], Does.Contain("ERROR"));
}
[Test]
public void Write_WithFormattedMessage_ShouldFormatCorrectly()
{
_logger.Info("Value: {0}", 42);
var output = _stringWriter.ToString();
Assert.That(output, Does.Contain("Value: 42"));
}
[Test]
public void Write_ShouldRespectMinLevel()
{
_logger.Info("Info message");
_logger.Debug("Debug message");
_logger.Trace("Trace message");
var output = _stringWriter.ToString();
Assert.That(output, Does.Contain("Info message"));
Assert.That(output, Does.Not.Contain("Debug message"));
Assert.That(output, Does.Not.Contain("Trace message"));
}
[Test]
public void Write_WithColorsEnabled_ShouldNotAffectOutputContent()
{
var coloredLogger = new ConsoleLogger("ColorLogger", LogLevel.Info, _stringWriter, false);
coloredLogger.Info("Colored message");
var output = _stringWriter.ToString();
Assert.That(output, Does.Contain("Colored message"));
}
[Test]
public void Write_AllLogLevels_ShouldFormatCorrectly()
{
_logger.Trace("Trace");
_logger.Debug("Debug");
_logger.Info("Info");
_logger.Warn("Warn");
_logger.Error("Error");
_logger.Fatal("Fatal");
var output = _stringWriter.ToString();
Assert.That(output, Does.Contain("INFO"));
Assert.That(output, Does.Contain("WARN"));
Assert.That(output, Does.Contain("ERROR"));
Assert.That(output, Does.Contain("FATAL"));
}
[Test]
public void Write_WithNestedException_ShouldIncludeFullException()
{
var innerException = new Exception("Inner exception");
var outerException = new Exception("Outer exception", innerException);
_logger.Error("Error", outerException);
var output = _stringWriter.ToString();
Assert.That(output, Does.Contain("Error"));
Assert.That(output, Does.Contain("Outer exception"));
Assert.That(output, Does.Contain("Inner exception"));
}
[Test]
public void Write_WithNullWriter_ShouldNotThrow()
{
var logger = new ConsoleLogger("TestLogger", LogLevel.Info, null, false);
Assert.DoesNotThrow(() => logger.Info("Test message"));
}
[Test]
public void Write_WithEmptyMessage_ShouldStillWrite()
{
_logger.Info("");
var output = _stringWriter.ToString();
Assert.That(output.Length, Is.GreaterThan(0));
}
}

View File

@ -0,0 +1,204 @@
using GFramework.Core.Abstractions.logging;
using GFramework.Core.logging;
using NUnit.Framework;
namespace GFramework.Core.Tests.logging;
[TestFixture]
public class LoggerFactoryTests
{
[Test]
public void ConsoleLoggerFactory_GetLogger_ShouldReturnConsoleLogger()
{
var factory = new ConsoleLoggerFactory();
var logger = factory.GetLogger("TestLogger", LogLevel.Info);
Assert.That(logger, Is.Not.Null);
Assert.That(logger, Is.InstanceOf<ConsoleLogger>());
Assert.That(logger.Name(), Is.EqualTo("TestLogger"));
}
[Test]
public void ConsoleLoggerFactory_GetLogger_WithDifferentNames_ShouldReturnDifferentLoggers()
{
var factory = new ConsoleLoggerFactory();
var logger1 = factory.GetLogger("Logger1");
var logger2 = factory.GetLogger("Logger2");
Assert.That(logger1.Name(), Is.EqualTo("Logger1"));
Assert.That(logger2.Name(), Is.EqualTo("Logger2"));
}
[Test]
public void ConsoleLoggerFactory_GetLogger_WithDefaultMinLevel_ShouldUseInfo()
{
var factory = new ConsoleLoggerFactory();
var logger = (ConsoleLogger)factory.GetLogger("TestLogger");
var stringWriter = new StringWriter();
var testLogger = new ConsoleLogger("TestLogger", LogLevel.Info, stringWriter, false);
testLogger.Debug("Debug message");
testLogger.Info("Info message");
var output = stringWriter.ToString();
Assert.That(output, Does.Not.Contain("Debug message"));
Assert.That(output, Does.Contain("Info message"));
}
[Test]
public void ConsoleLoggerFactoryProvider_CreateLogger_ShouldReturnLoggerWithProviderMinLevel()
{
var provider = new ConsoleLoggerFactoryProvider { MinLevel = LogLevel.Debug };
var logger = (ConsoleLogger)provider.CreateLogger("TestLogger");
var stringWriter = new StringWriter();
var testLogger = new ConsoleLogger("TestLogger", LogLevel.Debug, stringWriter, false);
testLogger.Debug("Debug message");
testLogger.Trace("Trace message");
var output = stringWriter.ToString();
Assert.That(output, Does.Contain("Debug message"));
Assert.That(output, Does.Not.Contain("Trace message"));
}
[Test]
public void ConsoleLoggerFactoryProvider_CreateLogger_ShouldUseProvidedName()
{
var provider = new ConsoleLoggerFactoryProvider();
var logger = provider.CreateLogger("MyLogger");
Assert.That(logger.Name(), Is.EqualTo("MyLogger"));
}
[Test]
public void LoggerFactoryResolver_Provider_ShouldHaveDefaultValue()
{
Assert.That(LoggerFactoryResolver.Provider, Is.Not.Null);
Assert.That(LoggerFactoryResolver.Provider, Is.InstanceOf<ConsoleLoggerFactoryProvider>());
}
[Test]
public void LoggerFactoryResolver_Provider_CanBeChanged()
{
var customProvider = new ConsoleLoggerFactoryProvider { MinLevel = LogLevel.Debug };
var originalProvider = LoggerFactoryResolver.Provider;
LoggerFactoryResolver.Provider = customProvider;
Assert.That(LoggerFactoryResolver.Provider, Is.SameAs(customProvider));
LoggerFactoryResolver.Provider = originalProvider;
}
[Test]
public void LoggerFactoryResolver_MinLevel_ShouldHaveDefaultValue()
{
Assert.That(LoggerFactoryResolver.MinLevel, Is.EqualTo(LogLevel.Info));
}
[Test]
public void LoggerFactoryResolver_MinLevel_CanBeChanged()
{
var originalLevel = LoggerFactoryResolver.MinLevel;
LoggerFactoryResolver.MinLevel = LogLevel.Debug;
Assert.That(LoggerFactoryResolver.MinLevel, Is.EqualTo(LogLevel.Debug));
LoggerFactoryResolver.MinLevel = originalLevel;
}
[Test]
public void ConsoleLoggerFactoryProvider_MinLevel_ShouldHaveDefaultValue()
{
var provider = new ConsoleLoggerFactoryProvider();
Assert.That(provider.MinLevel, Is.EqualTo(LogLevel.Info));
}
[Test]
public void ConsoleLoggerFactoryProvider_MinLevel_CanBeChanged()
{
var provider = new ConsoleLoggerFactoryProvider();
provider.MinLevel = LogLevel.Debug;
Assert.That(provider.MinLevel, Is.EqualTo(LogLevel.Debug));
}
[Test]
public void LoggerFactoryResolver_Provider_CreateLogger_ShouldUseProviderSettings()
{
var originalProvider = LoggerFactoryResolver.Provider;
var provider = new ConsoleLoggerFactoryProvider { MinLevel = LogLevel.Warning };
LoggerFactoryResolver.Provider = provider;
var logger = (ConsoleLogger)provider.CreateLogger("TestLogger");
var stringWriter = new StringWriter();
var testLogger = new ConsoleLogger("TestLogger", LogLevel.Warning, stringWriter, false);
testLogger.Warn("Warn message");
testLogger.Info("Info message");
var output = stringWriter.ToString();
Assert.That(output, Does.Contain("Warn message"));
Assert.That(output, Does.Not.Contain("Info message"));
LoggerFactoryResolver.Provider = originalProvider;
}
[Test]
public void LoggerFactoryResolver_MinLevel_AffectsNewLoggers()
{
var originalMinLevel = LoggerFactoryResolver.MinLevel;
LoggerFactoryResolver.MinLevel = LogLevel.Error;
var provider = LoggerFactoryResolver.Provider;
var logger = (ConsoleLogger)provider.CreateLogger("TestLogger");
var stringWriter = new StringWriter();
var testLogger = new ConsoleLogger("TestLogger", LogLevel.Error, stringWriter, false);
testLogger.Error("Error message");
testLogger.Warn("Warn message");
var output = stringWriter.ToString();
Assert.That(output, Does.Contain("Error message"));
Assert.That(output, Does.Not.Contain("Warn message"));
LoggerFactoryResolver.MinLevel = originalMinLevel;
}
[Test]
public void ConsoleLoggerFactory_MultipleLoggers_ShouldBeIndependent()
{
var factory = new ConsoleLoggerFactory();
var logger1 = factory.GetLogger("Logger1", LogLevel.Info);
var logger2 = factory.GetLogger("Logger2", LogLevel.Debug);
Assert.That(logger1.Name(), Is.EqualTo("Logger1"));
Assert.That(logger2.Name(), Is.EqualTo("Logger2"));
}
[Test]
public void ConsoleLoggerFactoryProvider_MinLevel_DoesNotAffectCreatedLogger()
{
var provider = new ConsoleLoggerFactoryProvider { MinLevel = LogLevel.Error };
var logger = provider.CreateLogger("TestLogger");
var stringWriter = new StringWriter();
var testLogger = new ConsoleLogger("TestLogger", LogLevel.Error, stringWriter, false);
testLogger.Error("Error message");
testLogger.Fatal("Fatal message");
var output = stringWriter.ToString();
Assert.That(output, Does.Contain("Error message"));
Assert.That(output, Does.Contain("Fatal message"));
}
}

View File

@ -0,0 +1,331 @@
using GFramework.Core.Abstractions.logging;
using GFramework.Core.logging;
using NUnit.Framework;
namespace GFramework.Core.Tests.logging;
[TestFixture]
public class LoggerTests
{
[SetUp]
public void SetUp()
{
_logger = new TestLogger("TestLogger", LogLevel.Info);
}
private TestLogger _logger = null!;
[Test]
public void Name_Should_ReturnLoggerName()
{
var name = _logger.Name();
Assert.That(name, Is.EqualTo("TestLogger"));
}
[Test]
public void Name_WithDefaultName_Should_ReturnRootLoggerName()
{
var defaultLogger = new TestLogger();
Assert.That(defaultLogger.Name(), Is.EqualTo("ROOT"));
}
[Test]
public void IsTraceEnabled_WithInfoMinLevel_Should_ReturnFalse()
{
Assert.That(_logger.IsTraceEnabled(), Is.False);
}
[Test]
public void IsDebugEnabled_WithInfoMinLevel_Should_ReturnFalse()
{
Assert.That(_logger.IsDebugEnabled(), Is.False);
}
[Test]
public void IsInfoEnabled_WithInfoMinLevel_Should_ReturnTrue()
{
Assert.That(_logger.IsInfoEnabled(), Is.True);
}
[Test]
public void IsWarnEnabled_WithInfoMinLevel_Should_ReturnTrue()
{
Assert.That(_logger.IsWarnEnabled(), Is.True);
}
[Test]
public void IsErrorEnabled_WithInfoMinLevel_Should_ReturnTrue()
{
Assert.That(_logger.IsErrorEnabled(), Is.True);
}
[Test]
public void IsFatalEnabled_WithInfoMinLevel_Should_ReturnTrue()
{
Assert.That(_logger.IsFatalEnabled(), Is.True);
}
[Test]
public void IsEnabledForLevel_WithValidLevel_Should_ReturnCorrectResult()
{
Assert.That(_logger.IsEnabledForLevel(LogLevel.Trace), Is.False);
Assert.That(_logger.IsEnabledForLevel(LogLevel.Debug), Is.False);
Assert.That(_logger.IsEnabledForLevel(LogLevel.Info), Is.True);
Assert.That(_logger.IsEnabledForLevel(LogLevel.Warning), Is.True);
Assert.That(_logger.IsEnabledForLevel(LogLevel.Error), Is.True);
Assert.That(_logger.IsEnabledForLevel(LogLevel.Fatal), Is.True);
}
[Test]
public void IsEnabledForLevel_WithInvalidLevel_Should_ThrowArgumentException()
{
Assert.Throws<ArgumentException>(() => { _logger.IsEnabledForLevel((LogLevel)999); });
}
[Test]
public void Trace_ShouldNotWrite_WhenTraceDisabled()
{
_logger.Trace("Trace message");
Assert.That(_logger.Logs.Count, Is.EqualTo(0));
}
[Test]
public void Trace_WithFormat_ShouldNotWrite_WhenTraceDisabled()
{
_logger.Trace("Formatted {0}", "message");
Assert.That(_logger.Logs.Count, Is.EqualTo(0));
}
[Test]
public void Trace_WithTwoArgs_ShouldNotWrite_WhenTraceDisabled()
{
_logger.Trace("Formatted {0} and {1}", "arg1", "arg2");
Assert.That(_logger.Logs.Count, Is.EqualTo(0));
}
[Test]
public void Trace_WithException_ShouldNotWrite_WhenTraceDisabled()
{
var exception = new Exception("Test exception");
_logger.Trace("Trace message", exception);
Assert.That(_logger.Logs.Count, Is.EqualTo(0));
}
[Test]
public void Debug_ShouldNotWrite_WhenDebugDisabled()
{
_logger.Debug("Debug message");
Assert.That(_logger.Logs.Count, Is.EqualTo(0));
}
[Test]
public void Debug_WithFormat_ShouldNotWrite_WhenDebugDisabled()
{
_logger.Debug("Formatted {0}", "message");
Assert.That(_logger.Logs.Count, Is.EqualTo(0));
}
[Test]
public void Info_ShouldWrite_WhenInfoEnabled()
{
_logger.Info("Info message");
Assert.That(_logger.Logs.Count, Is.EqualTo(1));
Assert.That(_logger.Logs[0].Level, Is.EqualTo(LogLevel.Info));
Assert.That(_logger.Logs[0].Message, Is.EqualTo("Info message"));
Assert.That(_logger.Logs[0].Exception, Is.Null);
}
[Test]
public void Info_WithFormat_ShouldWriteFormattedMessage()
{
_logger.Info("Formatted {0}", "message");
Assert.That(_logger.Logs.Count, Is.EqualTo(1));
Assert.That(_logger.Logs[0].Message, Is.EqualTo("Formatted message"));
}
[Test]
public void Info_WithTwoArgs_ShouldWriteFormattedMessage()
{
_logger.Info("Formatted {0} and {1}", "arg1", "arg2");
Assert.That(_logger.Logs.Count, Is.EqualTo(1));
Assert.That(_logger.Logs[0].Message, Is.EqualTo("Formatted arg1 and arg2"));
}
[Test]
public void Info_WithMultipleArgs_ShouldWriteFormattedMessage()
{
_logger.Info("Formatted {0}, {1}, {2}", "arg1", "arg2", "arg3");
Assert.That(_logger.Logs.Count, Is.EqualTo(1));
Assert.That(_logger.Logs[0].Message, Is.EqualTo("Formatted arg1, arg2, arg3"));
}
[Test]
public void Info_WithException_ShouldWriteMessageAndException()
{
var exception = new Exception("Test exception");
_logger.Info("Info message", exception);
Assert.That(_logger.Logs.Count, Is.EqualTo(1));
Assert.That(_logger.Logs[0].Message, Is.EqualTo("Info message"));
Assert.That(_logger.Logs[0].Exception, Is.SameAs(exception));
}
[Test]
public void Warn_ShouldWrite_WhenWarnEnabled()
{
_logger.Warn("Warn message");
Assert.That(_logger.Logs.Count, Is.EqualTo(1));
Assert.That(_logger.Logs[0].Level, Is.EqualTo(LogLevel.Warning));
Assert.That(_logger.Logs[0].Message, Is.EqualTo("Warn message"));
}
[Test]
public void Warn_WithFormat_ShouldWriteFormattedMessage()
{
_logger.Warn("Formatted {0}", "message");
Assert.That(_logger.Logs.Count, Is.EqualTo(1));
Assert.That(_logger.Logs[0].Message, Is.EqualTo("Formatted message"));
}
[Test]
public void Warn_WithException_ShouldWriteMessageAndException()
{
var exception = new Exception("Test exception");
_logger.Warn("Warn message", exception);
Assert.That(_logger.Logs.Count, Is.EqualTo(1));
Assert.That(_logger.Logs[0].Exception, Is.SameAs(exception));
}
[Test]
public void Error_ShouldWrite_WhenErrorEnabled()
{
_logger.Error("Error message");
Assert.That(_logger.Logs.Count, Is.EqualTo(1));
Assert.That(_logger.Logs[0].Level, Is.EqualTo(LogLevel.Error));
Assert.That(_logger.Logs[0].Message, Is.EqualTo("Error message"));
}
[Test]
public void Error_WithFormat_ShouldWriteFormattedMessage()
{
_logger.Error("Formatted {0}", "message");
Assert.That(_logger.Logs.Count, Is.EqualTo(1));
Assert.That(_logger.Logs[0].Message, Is.EqualTo("Formatted message"));
}
[Test]
public void Error_WithException_ShouldWriteMessageAndException()
{
var exception = new Exception("Test exception");
_logger.Error("Error message", exception);
Assert.That(_logger.Logs.Count, Is.EqualTo(1));
Assert.That(_logger.Logs[0].Exception, Is.SameAs(exception));
}
[Test]
public void Fatal_ShouldWrite_WhenFatalEnabled()
{
_logger.Fatal("Fatal message");
Assert.That(_logger.Logs.Count, Is.EqualTo(1));
Assert.That(_logger.Logs[0].Level, Is.EqualTo(LogLevel.Fatal));
Assert.That(_logger.Logs[0].Message, Is.EqualTo("Fatal message"));
}
[Test]
public void Fatal_WithFormat_ShouldWriteFormattedMessage()
{
_logger.Fatal("Formatted {0}", "message");
Assert.That(_logger.Logs.Count, Is.EqualTo(1));
Assert.That(_logger.Logs[0].Message, Is.EqualTo("Formatted message"));
}
[Test]
public void Fatal_WithException_ShouldWriteMessageAndException()
{
var exception = new Exception("Test exception");
_logger.Fatal("Fatal message", exception);
Assert.That(_logger.Logs.Count, Is.EqualTo(1));
Assert.That(_logger.Logs[0].Exception, Is.SameAs(exception));
}
[Test]
public void MultipleLogCalls_ShouldAccumulateLogs()
{
_logger.Info("Message 1");
_logger.Warn("Message 2");
_logger.Error("Message 3");
Assert.That(_logger.Logs.Count, Is.EqualTo(3));
Assert.That(_logger.Logs[0].Message, Is.EqualTo("Message 1"));
Assert.That(_logger.Logs[1].Message, Is.EqualTo("Message 2"));
Assert.That(_logger.Logs[2].Message, Is.EqualTo("Message 3"));
}
[Test]
public void Logger_WithTraceMinLevel_ShouldEnableAllLevels()
{
var traceLogger = new TestLogger("TraceLogger", LogLevel.Trace);
traceLogger.Trace("Trace");
traceLogger.Debug("Debug");
traceLogger.Info("Info");
traceLogger.Warn("Warn");
traceLogger.Error("Error");
traceLogger.Fatal("Fatal");
Assert.That(traceLogger.Logs.Count, Is.EqualTo(6));
}
[Test]
public void Logger_WithFatalMinLevel_ShouldDisableAllButFatal()
{
var fatalLogger = new TestLogger("FatalLogger", LogLevel.Fatal);
fatalLogger.Trace("Trace");
fatalLogger.Debug("Debug");
fatalLogger.Info("Info");
fatalLogger.Warn("Warn");
fatalLogger.Error("Error");
fatalLogger.Fatal("Fatal");
Assert.That(fatalLogger.Logs.Count, Is.EqualTo(1));
Assert.That(fatalLogger.Logs[0].Level, Is.EqualTo(LogLevel.Fatal));
}
}
public sealed class TestLogger : AbstractLogger
{
public TestLogger(string? name = null, LogLevel minLevel = LogLevel.Info) : base(name, minLevel)
{
}
public List<LogEntry> Logs { get; } = new();
protected override void Write(LogLevel level, string message, Exception? exception)
{
Logs.Add(new LogEntry(level, message, exception));
}
public sealed record LogEntry(LogLevel Level, string Message, Exception? Exception);
}

View File

@ -0,0 +1,40 @@
using GFramework.Game.Abstractions.ui;
using Godot;
namespace GFramework.Godot.ui;
/// <summary>
/// Godot UI注册表实现类用于管理PackedScene类型的UI资源注册和获取
/// </summary>
public class GodotUiRegistry : IWritableUiRegistry<PackedScene>
{
/// <summary>
/// 存储UI键值对的字典键为UI标识符值为对应的PackedScene对象
/// </summary>
private readonly Dictionary<string, PackedScene> _map = new(StringComparer.Ordinal);
/// <summary>
/// 注册UI场景到注册表中
/// </summary>
/// <param name="key">UI的唯一标识符</param>
/// <param name="scene">要注册的PackedScene对象</param>
/// <returns>返回当前UI注册表实例支持链式调用</returns>
public IWritableUiRegistry<PackedScene> Register(string key, PackedScene scene)
{
_map[key] = scene;
return this;
}
/// <summary>
/// 根据键获取已注册的UI场景
/// </summary>
/// <param name="uiKey">UI的唯一标识符</param>
/// <exception cref="KeyNotFoundException">当指定的键未找到对应的UI场景时抛出异常</exception>
/// <returns>对应的PackedScene对象</returns>
public PackedScene Get(string uiKey)
{
return !_map.TryGetValue(uiKey, out var scene)
? throw new KeyNotFoundException($"UI not registered: {uiKey}")
: scene;
}
}