获取自定义程序集属性不加载到当前的AppDomain(Getting custom assembly

2019-06-24 04:06发布

我创建了一个小的应用程序递归加载组件中,提供的目录,并阅读他们的自定义属性的集合。 主要是刚读DebuggableAttribute确定IsJITTrackingEnabled和IsJITOptimizerDisabled的设置,以确定是否该组件被释放的优化。

我当前的代码执行一次Assembly.LoadFrom到传递整个路径中,以组装和加载。 然后做在组件上的GetCustomAttributes获得可调试属性。 问题是,每个组件被加载到当前应用程序域。 所以,如果另一个文件夹使用相同的组件,它只是使用原来装的参考。 我想能够加载该程序集,读我所需要的属性,然后卸载它。 我试图创建一个新的应用程序域和加载组件到它,然后卸载组件后记无济于事。

我知道这一定是可能的,但我很茫然。 任何帮助将不胜感激。 我很乐意为您提供可能需要以及任何其他信息。

Answer 1:

简单的答案是,没有,有没有办法做到你的要求。

较长的答案是这样的:有一个特殊组件加载方法, 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版本没有任何意义相同的效果。



Answer 2:

您需要使用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;
}


Answer 3:

这是不可能永远卸载的组件在当前的AppDomain,这只是.NET的目的是不幸的工作方式。 这是即使ReflectionOnly负荷的情况下。 还有一个稍微做起皱说,除了你,然后需要使用GetCustomAttributesData而不是正常的GetCustomAttributes,因为后者需要方法的属性构造运行代码。 这可以使生活更加困难。

这应该工作的替代方案是使用塞西尔 ,它允许你检查总成没有通常意义上的实际加载它。 但是,这是一个很多额外的工作。



Answer 4:

我相信Assembly.ReflectionOnlyLoad是你在找什么。



文章来源: Getting custom assembly attributes without loading into current AppDomain