在不加载到当前 AppDomain 的情况下获取自定义程序集属性 [英] Getting custom assembly attributes without loading into current AppDomain

查看:19
本文介绍了在不加载到当前 AppDomain 的情况下获取自定义程序集属性的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我创建了一个小型应用程序,用于在提供的目录中递归加载程序集并读取它们的自定义属性集合.主要只是读取DebuggableAttribute来确定IsJITTrackingEnabled和IsJITOptimizerDisabled的设置,以确定程序集是否针对发布进行了优化.

I have created a small application to recursively load assemblies in a provided directory and read their custom attributes collection. Mainly just to read the DebuggableAttribute to determine the settings for IsJITTrackingEnabled and IsJITOptimizerDisabled to determine if the assembly is optimized for release.

我当前的代码执行一个 Assembly.LoadFrom 来传递程序集的整个路径并加载它.然后在程序集上执行 GetCustomAttributes 以获取可调试属性.问题是每个程序集都被加载到当前的应用程序域中.因此,如果另一个文件夹使用相同的程序集,它只使用最初加载的引用.我希望能够加载程序集,读取我需要的属性,然后卸载它.我尝试创建一个新的应用程序域并将程序集加载到其中,然后卸载程序集后记无济于事.

My current code does an Assembly.LoadFrom to pass-in the entire path to the assembly and load it. Then does a GetCustomAttributes on the assembly to get the debuggable attribute. The problem is that each assembly gets loaded into the current appdomain. So, if another folder uses the same assembly it just uses the originally loaded reference. I would like to be able to load the assembly, read the properties I need, then unload it. I have tries creating a new appdomain and loading the assemblies into it then unloading the assembly afterword to no avail.

我知道这一定是可能的,但我不知所措.任何帮助将不胜感激.我也很乐意提供您可能需要的任何其他信息.

I know this must be possible but I am at a loss. Any help would be greatly appreciated. I'd be happy to provide any other information you may need as well.

推荐答案

简短的回答是,不,没有办法按照您的要求去做.

The short answer is, no, there's no way to do what you're asking.

较长的答案是这样的:有一种特殊的程序集加载方法,Assembly.ReflectionOnlyLoad(),它使用仅反射"加载上下文.这使您可以加载无法执行但可以读取其元数据的程序集.

The longer answer is this: There is a special assembly loading method, Assembly.ReflectionOnlyLoad(), which uses a "reflection-only" load context. This lets you load assemblies that cannot be executed, but can have their metadata read.

在您的情况下(显然,在我自己能想到的每个用例中),它并不是那么有用.您无法从此类程序集中获取类型化属性,只能获取 CustomAttributeData.该类没有提供任何过滤特定属性的好方法(我能想到的最好方法是将其转换为字符串并使用 StartsWith("[System.Diagnostics.Debuggable");

In your case (and, apparently, in every use case I could come up with myself) it's not really that helpful. You cannot get typed attributes from this kind of assembly, only CustomAttributeData. That class doesn't provide any good way to filter for a specific attribute (the best I could come up with was to cast it to a string and use StartsWith("[System.Diagnostics.Debuggable");

更糟糕的是,仅反射加载不会加载任何依赖程序集,但它会强制您手动执行.这使得它客观上比你现在所做的更糟糕;至少现在你可以自动加载依赖项.

Even worse, a reflection-only load does not load any dependency assemblies, but it forces you to do it manually. That makes it objectively worse than what you're doing now; at least now you get the dependency loading automatically.

(另外,我之前的回答提到了 MEF;我错了,MEF 似乎包含大量自定义反射代码来完成这项工作.)

(Also, my previous answer made reference to MEF; I was wrong, it appears that MEF includes a whole ton of custom reflection code to make this work.)

最终,一旦加载程序集,您就无法卸载它.您需要卸载整个应用域,如这篇 MSDN 文章.

Ultimately, you cannot unload an assembly once it has been loaded. You need to unload the entire app domain, as described in this MSDN article.

更新:

如评论中所述,我能够通过仅反射加载(和正常加载)获取您需要的属性信息,但缺少类型化的属性元数据使其非常痛苦.

As noted in the comments, I was able to get the attribute information you needed via the reflection-only load (and a normal load) but the lack of typed attribute metadata makes it a serious pain.

如果加载到正常的程序集上下文中,您可以很容易地获得所需的信息:

If loaded into a normal assembly context, you can get the information you need easily enough:

var d = a.GetCustomAttributes(typeof(DebuggableAttribute), false) as DebuggableAttribute;
var tracking = d.IsJITTrackingEnabled;
var optimized = !d.IsJITOptimizerDisabled;

如果加载到仅反射上下文中,您就可以做一些工作;您必须弄清楚属性构造函数采用的形式,知道默认值是什么,并结合这些信息得出每个属性的最终值.您可以像这样获得所需的信息:

If loaded into a reflection-only context, you get to do some work; you have to figure out the form that the attribute constructor took, know what the default values are, and combine that information to come up with the final values of each property. You get the information you need like this:

var d2 = a.GetCustomAttributesData()
         .SingleOrDefault(x => x.ToString()
                                .StartsWith("[System.Diagnostics.DebuggableAttribute"));

从那里,您需要检查 ConstructorArguments 以查看调用了哪个构造函数:这个 带一个参数或 这个 有两个参数.然后,您可以使用适当参数的值来确定您感兴趣的两个属性将采用的值:

From there, you need to check the ConstructorArguments to see which constructor was called: this one with one argument or this one with two arguments. You can then use the values of the appropriate parameters to figure out what values the two properties you are interested in would have taken:

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 可能会覆盖构造函数上设置的那些,例如:

Finally, you need to check for NamedArguments that might override those set on the constructor, using for example:

var arg = NamedArguments.SingleOrDefault(x => x.MemberInfo.Name.Equals("IsJITOptimizerDisabled"));
var optimized = (arg == null || !((bool)arg.TypedValue.Value));

最后一点,如果您在 .NET 2.0 或更高版本下运行它,并且还没有看到,MSDN 在 DebuggingModes 文档:

On one final note, if you are running this under .NET 2.0 or higher, and haven't already seen in, MSDN points this out in the DebuggingModes documentation:

在.NET Framework 2.0版中,始终生成JIT跟踪信息,该标志与Default效果相同,只是IsJITTrackingEnabled属性为false,在2.0版中没有意义.

In the .NET Framework version 2.0, JIT tracking information is always generated, and this flag has the same effect as Default with the exception of the IsJITTrackingEnabled property being false, which has no meaning in version 2.0.

这篇关于在不加载到当前 AppDomain 的情况下获取自定义程序集属性的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆