fix(di): use factory lambdas for internal-ctor services

C3 bootstrap throws "A suitable constructor for type
HellionChat.Ipc.ExtraChat could not be located" because
Microsoft.Extensions.DependencyInjection's ActivatorUtilities only
binds to PUBLIC constructors via reflection. ExtraChat is a public
class with an internal ctor; Commands and StatusBar are internal
classes whose implicit default ctor inherits class accessibility
(internal); every IHostedService adapter is `internal sealed class
X(deps)` with a primary ctor that is also internal.

The fix routes all eight singletons and all seven hosted-service
adapters through factory lambdas. `new T(...)` inside the
PluginHostFactory namespace sees the internal surface, so the
container never has to reflect over internal ctors.
This commit is contained in:
2026-05-17 08:20:02 +02:00
parent 169168cea9
commit 0fe66d2c3c
+41 -15
View File
@@ -86,14 +86,22 @@ internal static class PluginHostFactory
// constraint; ctors that need a Plugin backref go through a factory // constraint; ctors that need a Plugin backref go through a factory
// lambda that resolves Plugin from the container. // lambda that resolves Plugin from the container.
// ----------------------------------------------------------------- // -----------------------------------------------------------------
services.AddSingleton<IPlatformUtil, DalamudPlatformUtil>(); // Factory lambdas across the board: Microsoft.Extensions.DependencyInjection's
services.AddSingleton<IPluginLogProxy, DalamudPluginLogProxy>(); // ActivatorUtilities only inspects PUBLIC constructors via reflection,
services.AddSingleton<FileDialogManager>(); // and several HellionChat classes are `internal sealed` with implicit-
services.AddSingleton<Commands>(); // internal default ctors (Commands, StatusBar) or explicitly `internal`
services.AddSingleton<FontManager>(); // ctors on public classes (ExtraChat). The lambda body compiles inside
services.AddSingleton<StatusBar>(); // the HellionChat namespace, so `new T()` sees the internal surface.
services.AddSingleton<IpcManager>(); services.AddSingleton<IPlatformUtil>(_ => new DalamudPlatformUtil());
services.AddSingleton<ExtraChat>(); services.AddSingleton<IPluginLogProxy>(sp => new DalamudPluginLogProxy(
sp.GetRequiredService<IPluginLog>()
));
services.AddSingleton<FileDialogManager>(_ => new FileDialogManager());
services.AddSingleton(_ => new Commands());
services.AddSingleton(_ => new FontManager());
services.AddSingleton(_ => new StatusBar());
services.AddSingleton(_ => new IpcManager());
services.AddSingleton(_ => new ExtraChat());
services.AddSingleton(sp => new ThemeRegistry( services.AddSingleton(sp => new ThemeRegistry(
Path.Combine( Path.Combine(
@@ -149,13 +157,31 @@ internal static class PluginHostFactory
// making the services themselves implement IHostedService (Lightless' // making the services themselves implement IHostedService (Lightless'
// pattern) — DI-2a leaves service classes untouched. // pattern) — DI-2a leaves service classes untouched.
// ----------------------------------------------------------------- // -----------------------------------------------------------------
services.AddHostedService<FontManagerInitHostedService>(); // Same internal-ctor pitfall as the singletons above - the adapter
services.AddHostedService<ThemeRegistryInitHostedService>(); // classes are `internal sealed` with primary constructors, so the
services.AddHostedService<IpcManagerInitHostedService>(); // direct AddHostedService<T>() overload's ActivatorUtilities fails.
services.AddHostedService<TypingIpcInitHostedService>(); services.AddHostedService(sp => new FontManagerInitHostedService(
services.AddHostedService<ExtraChatInitHostedService>(); sp.GetRequiredService<FontManager>()
services.AddHostedService<MessageManagerInitHostedService>(); ));
services.AddHostedService<AutoTellTabsServiceInitHostedService>(); services.AddHostedService(sp => new ThemeRegistryInitHostedService(
sp.GetRequiredService<ThemeRegistry>()
));
services.AddHostedService(sp => new IpcManagerInitHostedService(
sp.GetRequiredService<IpcManager>()
));
services.AddHostedService(sp => new TypingIpcInitHostedService(
sp.GetRequiredService<TypingIpc>()
));
services.AddHostedService(sp => new ExtraChatInitHostedService(
sp.GetRequiredService<ExtraChat>()
));
services.AddHostedService(sp => new MessageManagerInitHostedService(
sp.GetRequiredService<IDalamudPluginInterface>(),
sp.GetRequiredService<MessageManager>()
));
services.AddHostedService(sp => new AutoTellTabsServiceInitHostedService(
sp.GetRequiredService<AutoTellTabsService>()
));
} }
} }