获取自定义装配属性而不加载到当前AppDomain中 [英] Getting custom assembly attributes without loading into current AppDomain

查看:172
本文介绍了获取自定义装配属性而不加载到当前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传递,在整个路径中汇编并加载它。然后在Assembly上获取一个GetCustomAttributes来获取debuggable属性。问题是每个程序集都加载到当前的应用程序域中。所以,如果另一个文件夹使用相同的程序集,它只是使用最初加载的引用。我想要能够加载程序集,读取我需要的属性,然后卸载它。我尝试创建一个新的应用程序域,然后加载程序集到它然后卸载程序集后果无效。

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.

推荐答案

简短的回答是,不,

更长的答案是这样的:有一个特殊的加载方法, 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");

更糟糕的是,仅反射加载不会加载任何依赖程序集,但是它强制您手动执行 em>

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中,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:


始终生成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天全站免登陆