我正在构建一个WPF工具,该工具将通过反射分析目标应用程序的程序集。
到目前为止,我一直在使用Assembly.Load
等方法来加载目标程序集。这样做还可以,但它有几个限制:我希望能够重建目标应用程序并“刷新”工具以重新分析新构建的程序集。这目前不起作用,因为程序集在加载时被锁定,并且直到工具退出后才被释放。这也排除了重新加载新构建的程序集。
我认为我可以创建一个临时AppDomain,将程序集加载到其中,执行我想要的反射操作,然后卸载该域。
我的问题在于我无法让它正常工作。我尝试了很多变化,得到了如下结果:
- 加载到当前应用程序域,而不是我明确创建的域中
- 请求的程序集加载错误
- 加载工具的程序集时出错(?)
例如,遵循此处的建议:Create custom AppDomain and add assemblies to it
我创建了一个SimpleAssemblyLoader
,如下所示:
public class SimpleAssemblyLoader : MarshalByRefObject
{
public Assembly Load(string path)
{
ValidatePath(path);
return Assembly.Load(path);
}
public Assembly LoadFrom(string path)
{
ValidatePath(path);
return Assembly.LoadFrom(path);
}
public Assembly UnsafeLoadFrom(string path)
{
ValidatePath(path);
return Assembly.UnsafeLoadFrom(path);
}
private void ValidatePath(string path)
{
if (path == null) throw new ArgumentNullException(nameof(path));
if (!System.IO.File.Exists(path))
throw new ArgumentException($"path \"{path}\" does not exist");
}
}
...并在调用方法中使用它:
private static AppDomain MakeDomain(string name, string targetPath, string toolPath)
{
var appDomain =
AppDomain.CreateDomain(name, AppDomain.CurrentDomain.Evidence, new AppDomainSetup
{
ApplicationBase = targetPath,
PrivateBinPath = toolPath,
LoaderOptimization = LoaderOptimization.MultiDomainHost
},
new PermissionSet(PermissionState.Unrestricted));
return appDomain;
}
/// <summary>
///
/// </summary>
/// <param name="targetPath">Location of assemblies to analyze</param>
/// <param name="toolPath">Location of this tool</param>
/// <param name="file">Filename of assembly to analyze</param>
/// <returns></returns>
public string[] Test(string targetPath, string toolPath, string file)
{
var dom = MakeDomain("TestDomain", targetPath, toolPath);
var assemblyLoader = (SimpleAssemblyLoader)dom.CreateInstanceAndUnwrap(typeof(SimpleAssemblyLoader).Assembly.FullName, typeof(SimpleAssemblyLoader).FullName);
var path = Path.Combine(targetPath, file);
var assembly = assemblyLoader.LoadFrom(path);
var types = assembly.GetTypes();
List<string> methods = new List<string>();
foreach (var type in types)
{
foreach (var method in type.GetMethods(BindingFlags.Instance|BindingFlags.Public))
{
methods.Add(method.Name);
}
}
AppDomain.Unload(dom);
return methods.ToArray();
}
当工具应用程序启动时,它无法实例化SimpleAssemblyLoader,并报告与工具的程序集相关的“文件未找到”异常 - 显然尝试将工具的程序集加载到新域中。我做错了什么?如何修复?