diff --git a/GFramework.Core.Tests/Logging/ConfigurableLoggerFactoryTests.cs b/GFramework.Core.Tests/Logging/ConfigurableLoggerFactoryTests.cs
index 074c9a02..b20dd184 100644
--- a/GFramework.Core.Tests/Logging/ConfigurableLoggerFactoryTests.cs
+++ b/GFramework.Core.Tests/Logging/ConfigurableLoggerFactoryTests.cs
@@ -36,6 +36,24 @@ public sealed class ConfigurableLoggerFactoryTests
});
}
+ ///
+ /// 验证当配置输入把 appenders 集合中的某个元素反序列化为 时,工厂会抛出可诊断异常。
+ ///
+ [Test]
+ public void CreateFactory_ShouldThrowInvalidOperationException_WhenAppenderEntryIsNull()
+ {
+ var config = LoggingConfigurationLoader.LoadFromJsonString(
+ """
+ {
+ "appenders": [ null ]
+ }
+ """);
+
+ var exception = Assert.Throws(() => LoggingConfigurationLoader.CreateFactory(config));
+
+ Assert.That(exception!.Message, Is.EqualTo("Appender configuration cannot be null."));
+ }
+
///
/// 验证在未命中命名空间覆盖时,调用方传入的默认最小级别会作为最终 logger 级别的下限参与计算。
///
diff --git a/GFramework.Core/Logging/ConfigurableLoggerFactory.cs b/GFramework.Core/Logging/ConfigurableLoggerFactory.cs
index 5e4b497e..4d1fd064 100644
--- a/GFramework.Core/Logging/ConfigurableLoggerFactory.cs
+++ b/GFramework.Core/Logging/ConfigurableLoggerFactory.cs
@@ -16,6 +16,8 @@ internal sealed class ConfigurableLoggerFactory : ILoggerFactory, IDisposable
/// 初始化一个基于日志配置创建输出管线的工厂实例。
///
/// 日志配置。
+ /// 为 。
+ /// 配置中的某个 Appender 项为 。
public ConfigurableLoggerFactory(LoggingConfiguration config)
{
_config = config ?? throw new ArgumentNullException(nameof(config));
@@ -23,7 +25,13 @@ internal sealed class ConfigurableLoggerFactory : ILoggerFactory, IDisposable
// 反序列化输入可能显式把集合写成 null,这里统一归一化为可安全枚举的空集合。
_config.Appenders ??= [];
_config.LoggerLevels ??= new Dictionary(StringComparer.Ordinal);
- _appenders = _config.Appenders.Select(LoggingConfigurationLoader.CreateAppender).ToArray();
+
+ // 外部配置可能把集合项反序列化为 null,这里先给出可诊断异常,避免后续工厂链路出现不清晰的空引用失败。
+ _appenders = _config.Appenders
+ .Select(static appenderConfig => appenderConfig ??
+ throw new InvalidOperationException("Appender configuration cannot be null."))
+ .Select(LoggingConfigurationLoader.CreateAppender)
+ .ToArray();
}
///
diff --git a/GFramework.Godot/Architectures/AbstractArchitecture.cs b/GFramework.Godot/Architectures/AbstractArchitecture.cs
index 668c84ce..1beb8609 100644
--- a/GFramework.Godot/Architectures/AbstractArchitecture.cs
+++ b/GFramework.Godot/Architectures/AbstractArchitecture.cs
@@ -2,8 +2,6 @@
using GFramework.Core.Abstractions.Environment;
using GFramework.Core.Architectures;
using GFramework.Core.Constants;
-using GFramework.Godot.Extensions;
-using Godot;
namespace GFramework.Godot.Architectures;
@@ -165,7 +163,7 @@ public abstract class AbstractArchitecture(
{
try
{
- await DestroyAsync();
+ await DestroyAsync().ConfigureAwait(false);
}
catch (Exception ex)
{
diff --git a/docs/zh-CN/godot/setting.md b/docs/zh-CN/godot/setting.md
index f1c75ae5..8187f303 100644
--- a/docs/zh-CN/godot/setting.md
+++ b/docs/zh-CN/godot/setting.md
@@ -378,7 +378,7 @@ public class AudioManager : Node
);
}
- private void SetMasterVolume(float linearVolume)
+ private async void SetMasterVolume(float linearVolume)
{
var settings = new AudioSettings { MasterVolume = linearVolume };
var audioSettings = new GodotAudioSettings(settings, new AudioBusMap());
@@ -419,7 +419,7 @@ public class CustomAudioManager : Node
);
}
- private void SetMasterVolume(float linearVolume)
+ private async void SetMasterVolume(float linearVolume)
{
var audioSettingsData = new AudioSettings { MasterVolume = linearVolume };
var audioSettings = new GodotAudioSettings(audioSettingsData, _customBusMap);