Addresses code quality review of a7f0732:
- LoadedPlugin now holds the AssemblyLoadContext explicitly so Task 10
can call Unload() for hot reload (Critical)
- LoadedPlugin.Error is Exception? to match PluginDiscoveryResult and
preserve stack traces; synthetic failures build FileNotFoundException
and InvalidOperationException (Important)
- PluginLoader falls back to ReflectionTypeLoadException.Types if
GetTypes() can't fully resolve (Important)
- Hardcoded abstractions assembly name is now a const (Minor)
32 lines
1.2 KiB
C#
32 lines
1.2 KiB
C#
using System.Reflection;
|
|
using System.Runtime.Loader;
|
|
|
|
namespace AcDream.Core.Plugins;
|
|
|
|
/// <summary>
|
|
/// Collectible ALC for a single plugin. Resolves assemblies from the plugin's
|
|
/// own directory EXCEPT for AcDream.Plugin.Abstractions, which must come from
|
|
/// the default (host) context so type identity for IAcDreamPlugin is preserved.
|
|
/// </summary>
|
|
internal sealed class PluginAssemblyLoadContext : AssemblyLoadContext
|
|
{
|
|
private const string AbstractionsAssemblyName = "AcDream.Plugin.Abstractions";
|
|
|
|
private readonly AssemblyDependencyResolver _resolver;
|
|
|
|
public PluginAssemblyLoadContext(string pluginDirectory, string pluginEntryPath)
|
|
: base(name: pluginDirectory, isCollectible: true)
|
|
{
|
|
_resolver = new AssemblyDependencyResolver(pluginEntryPath);
|
|
}
|
|
|
|
protected override Assembly? Load(AssemblyName assemblyName)
|
|
{
|
|
// Share the abstractions assembly with the host — do NOT reload it in the plugin ALC
|
|
if (assemblyName.Name == AbstractionsAssemblyName)
|
|
return null;
|
|
|
|
var path = _resolver.ResolveAssemblyToPath(assemblyName);
|
|
return path is null ? null : LoadFromAssemblyPath(path);
|
|
}
|
|
}
|