【发布时间】:2023-02-06 03:39:40
【问题描述】:
基于this Microsoft example,我如何通过在AssemblyLoadContext类中实现它来Unload加载程序集? (考虑到他们在全球List<Assembly>。
我尝试了一些方法,this example too 但似乎没有什么能真正释放 dll 并让我在不关闭主应用程序的情况下用新的“删除它”或“覆盖它”。
实际加载代码是这样的:
static IEnumerable<ICommand> Plugs = Enumerable.Empty<ICommand>();
static readonly List<Assembly> PluginAssemblies = new();
static readonly List<string> PluginPath = new();
PluginPath.Add("C:\\...\\Plugin1.dll");
PluginPath.Add("C:\\...\\Plugin2.dll");
PluginPath.Add("C:\\...\\Plugin3.dll");
PluginPath.Add("C:\\...\\Plugin4.dll");
PluginPath.ForEach(P => { PluginAssemblies.Add(LoadPlugin(P)); });
Plugs = Plugs.Concat(PluginAssemblies.SelectMany(A => CreateCommands(A)));
这些是示例中的函数:
static Assembly LoadPlugin(string relativePath)
{
// Navigate up to the solution root
string root = Path.GetFullPath(Path.Combine(
Path.GetDirectoryName(
Path.GetDirectoryName(
Path.GetDirectoryName(
Path.GetDirectoryName(
Path.GetDirectoryName(typeof(Program).Assembly.Location)))))));
string pluginLocation = Path.GetFullPath(Path.Combine(root, relativePath.Replace('\\', Path.DirectorySeparatorChar)));
Console.WriteLine($"Loading commands from: {pluginLocation}");
PluginLoadContext loadContext = new PluginLoadContext(pluginLocation);
return loadContext.LoadFromAssemblyName(new AssemblyName(Path.GetFileNameWithoutExtension(pluginLocation)));
}
static IEnumerable<ICommand> CreateCommands(Assembly assembly)
{
int count = 0;
foreach (Type type in assembly.GetTypes())
{
if (typeof(ICommand).IsAssignableFrom(type))
{
ICommand result = Activator.CreateInstance(type) as ICommand;
if (result != null)
{
count++;
yield return result;
}
}
}
if (count == 0)
{
string availableTypes = string.Join(",", assembly.GetTypes().Select(t => t.FullName));
throw new ApplicationException(
$"Can't find any type which implements ICommand in {assembly} from {assembly.Location}.\n" +
$"Available types: {availableTypes}");
}
}
using System;
using System.Reflection;
using System.Runtime.Loader;
namespace AppWithPlugin
{
class PluginLoadContext : AssemblyLoadContext
{
private AssemblyDependencyResolver _resolver;
public PluginLoadContext(string pluginPath)
{
_resolver = new AssemblyDependencyResolver(pluginPath);
}
protected override Assembly Load(AssemblyName assemblyName)
{
string assemblyPath = _resolver.ResolveAssemblyToPath(assemblyName);
if (assemblyPath != null)
{
return LoadFromAssemblyPath(assemblyPath);
}
return null;
}
protected override IntPtr LoadUnmanagedDll(string unmanagedDllName)
{
string libraryPath = _resolver.ResolveUnmanagedDllToPath(unmanagedDllName);
if (libraryPath != null)
{
return LoadUnmanagedDllFromPath(libraryPath);
}
return IntPtr.Zero;
}
}
}
【问题讨论】:
-
您的目标是什么版本的 .NET? AppDomains 和程序集加载的行为随着 .NET Core 发生了很大变化,并被带到 .NET 5 及更高版本中。
标签: c# .net .net-core dll .net-assembly