我创建了一个小的应用程序递归加载组件中,提供的目录,并阅读他们的自定义属性的集合。 主要是刚读DebuggableAttribute确定IsJITTrackingEnabled和IsJITOptimizerDisabled的设置,以确定是否该组件被释放的优化。
我当前的代码执行一次Assembly.LoadFrom到传递整个路径中,以组装和加载。 然后做在组件上的GetCustomAttributes获得可调试属性。 问题是,每个组件被加载到当前应用程序域。 所以,如果另一个文件夹使用相同的组件,它只是使用原来装的参考。 我想能够加载该程序集,读我所需要的属性,然后卸载它。 我试图创建一个新的应用程序域和加载组件到它,然后卸载组件后记无济于事。
我知道这一定是可能的,但我很茫然。 任何帮助将不胜感激。 我很乐意为您提供可能需要以及任何其他信息。
简单的答案是,没有,有没有办法做到你的要求。
较长的答案是这样的:有一个特殊组件加载方法, Assembly.ReflectionOnlyLoad()
它使用“反射仅”加载上下文。 这使您可以加载不能执行组件,但可以有自己的元数据读取。
在你的情况(和,显然,在每次使用情况下,我可以拿出自己)它不是真的那么有用。 您不能从这种组装,只得到类型的属性CustomAttributeData
。 那类不提供特定属性(我能想出是将它转换为字符串,并用最好的过滤什么好的办法StartsWith("[System.Diagnostics.Debuggable");
更糟的是,一个只反射加载不加载任何依赖组件,但它迫使你做手工 。 这使得它比你现在正在做什么客观的差; 至少现在你自动获得依赖加载。
(另外,我以前的答复提及MEF,我错了,看来MEF包括整个吨的自定义反射代码来完成这项工作。)
最终,一旦被加载,你不能卸载的组件。 您需要卸载整个应用程序域 ,如在此MSDN文章。
更新:
正如在评论中指出,我能够让你通过只反射载荷(标准载荷),但缺少类型属性的元数据所需要的属性信息,使其成为一个严重的疼痛。
如果加载到一个正常的装配情况下,你可以得到你需要足够轻松的信息:
var d = a.GetCustomAttributes(typeof(DebuggableAttribute), false) as DebuggableAttribute;
var tracking = d.IsJITTrackingEnabled;
var optimized = !d.IsJITOptimizerDisabled;
如果加载到只反射上下文,你做一些工作; 你要搞清楚的是,属性构造所采取的形式,知道的默认值,并结合这些信息拿出每个属性的最终值。 你得到你所需要的是这样的信息:
var d2 = a.GetCustomAttributesData()
.SingleOrDefault(x => x.ToString()
.StartsWith("[System.Diagnostics.DebuggableAttribute"));
从那里,你需要检查ConstructorArguments
来看看被称为其构造函数: 这个有一个参数或这一个带有两个参数。 然后,您可以使用相应的参数值找出哪些值两个属性您有兴趣将采取:
if (d2.ConstructorArguments.Count == 1)
{
var mode = d2.ConstructorArguments[0].Value as DebuggableAttribute.DebuggingModes;
// Parse the modes enumeration and figure out the values.
}
else
{
var tracking = (bool)d2.ConstructorArguments[0].Value;
var optimized = !((bool)d2.ConstructorArguments[1].Value);
}
最后,你需要检查NamedArguments
可能覆盖在构造函数的集合,例如使用:
var arg = NamedArguments.SingleOrDefault(x => x.MemberInfo.Name.Equals("IsJITOptimizerDisabled"));
var optimized = (arg == null || !((bool)arg.TypedValue.Value));
在最后一个音符,如果你是在.NET 2.0或更高版本上运行这一点,并没有已经看到,MSDN点在这一点DebuggingModes
文档:
在.NET Framework 2.0版时,总是产生JIT跟踪信息,而该标志为默认与IsJITTrackingEnabled财产是虚假的例外,它在2.0版本没有任何意义相同的效果。
您需要使用Assembly.ReflectionOnlyLoad
。
这里有一些MSDN注意 ,显示了如何使用它:
using System;
using System.IO;
using System.Reflection;
public class ReflectionOnlyLoadTest
{
public ReflectionOnlyLoadTest(String rootAssembly) {
m_rootAssembly = rootAssembly;
}
public static void Main(String[] args)
{
if (args.Length != 1) {
Console.WriteLine("Usage: Test assemblyPath");
return;
}
try {
ReflectionOnlyLoadTest rolt = new ReflectionOnlyLoadTest(args[0]);
rolt.Run();
}
catch (Exception e) {
Console.WriteLine("Exception: {0}!!!", e.Message);
}
}
internal void Run() {
AppDomain curDomain = AppDomain.CurrentDomain;
curDomain.ReflectionOnlyPreBindAssemblyResolve += new ResolveEventHandler(MyReflectionOnlyResolveEventHandler);
Assembly asm = Assembly.ReflectionOnlyLoadFrom(m_rootAssembly);
// force loading all the dependencies
Type[] types = asm.GetTypes();
// show reflection only assemblies in current appdomain
Console.WriteLine("------------- Inspection Context --------------");
foreach (Assembly a in curDomain.ReflectionOnlyGetAssemblies())
{
Console.WriteLine("Assembly Location: {0}", a.Location);
Console.WriteLine("Assembly Name: {0}", a.FullName);
Console.WriteLine();
}
}
private Assembly MyReflectionOnlyResolveEventHandler(object sender, ResolveEventArgs args) {
AssemblyName name = new AssemblyName(args.Name);
String asmToCheck = Path.GetDirectoryName(m_rootAssembly) + "\\" + name.Name + ".dll";
if (File.Exists(asmToCheck)) {
return Assembly.ReflectionOnlyLoadFrom(asmToCheck);
}
return Assembly.ReflectionOnlyLoad(args.Name);
}
private String m_rootAssembly;
}
这是不可能永远卸载的组件在当前的AppDomain,这只是.NET的目的是不幸的工作方式。 这是即使ReflectionOnly负荷的情况下。 还有一个稍微做起皱说,除了你,然后需要使用GetCustomAttributesData而不是正常的GetCustomAttributes,因为后者需要方法的属性构造运行代码。 这可以使生活更加困难。
这应该工作的替代方案是使用塞西尔 ,它允许你检查总成没有通常意义上的实际加载它。 但是,这是一个很多额外的工作。
我相信Assembly.ReflectionOnlyLoad是你在找什么。