C# · 12月 29, 2021

c# – 获取自定义的程序集属性,而不加载到当前的AppDomain中

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

我当前的代码是一个Assembly.LoadFrom,将整个路径传递给程序集并加载它.然后在程序集上执行GetCustomAttributes以获取可调试的属性.问题是每个程序集都被加载到当前的应用程序域中.所以,如果另一个文件夹使用相同的程序集,它只是使用原来加载的引用.我想要加载程序集,读取我需要的属性,然后卸载它.我已经尝试创建一个新的应用程序域并加载程序集,然后卸载程序集后无效.

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

解决方法 简单的答案是,不,没有办法做你所要求的.

更长的答案是:有一个特殊的装配加载方法Assembly.ReflectionOnlyLoad(),它使用“仅反射”加载上下文.这样可以加载不能执行的程序集,但可以读取其元数据.

在你的情况下(显而易见,在每一个使用情况下,我都可以想出自己),这不是真的有用.您不能从此类程序集中获取类型属性,只能从CustomAttributeData中获取类型属性.该类不提供任何好的方法来过滤特定的属性(最好的办法是将其转换为字符串,并使用StartsWith(“[System.Diagnostics.Debuggable”);

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

(此外,我以前的答复提到了MEF;我错了,MEF似乎包含了一整套自定义的反思代码,使其成为可能.)

最终,加载程序集后,您无法卸载程序集.您需要卸载整个应用程序域,如this MSDN article.所述

更新:

如评论中所述,我能够通过反射唯一的加载(和正常的加载)获取所需的属性信息,但缺少类型的属性元数据使其成为严重的痛苦.

如果加载到正常的汇编环境中,您可以轻松获取所需的信息:

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以查看调用哪个构造函数:this one具有一个参数或this one两个参数.然后,您可以使用适当参数的值来确定您感兴趣的两个属性值将被采用的值:

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文档中指出:

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.