代码之家  ›  专栏  ›  技术社区  ›  Drew Noakes

如何为反射操作加载.NET程序集,然后卸载它?

  •  36
  • Drew Noakes  · 技术社区  · 16 年前

    我正在编写一个工具来报告有关在客户机系统中跨环境和区域部署的.NET应用程序的信息。

    我想读取这些程序集中程序集属性的值。

    这可以通过使用 Assembly.ReflectionOnlyLoad 但是,即使这种方法也会使程序集保持加载状态。这里的问题是,我不能从不同的路径加载两个具有相同名称的程序集,因此自然我不能比较部署在不同系统中的相同应用程序。

    在这一点上,我假设解决方案将涉及使用临时的 AppDomain S.

    有人能详细说明如何将程序集加载到另一个程序集中吗? 应用程序域 ,从中读取属性,然后卸载 应用程序域 ?

    这需要适用于文件系统上的程序集以及URL地址上的程序集。

    5 回复  |  直到 8 年前
        1
  •  48
  •   Tamas Czinege    16 年前

    MSDN documentation of System.Reflection.Assembly.ReflectionOnlyLoad (String) :

    仅反射上下文是否 不同于其他上下文。 加载到中的程序集 上下文只能由 正在卸载应用程序域。

    因此,恐怕卸载程序集的唯一方法是卸载应用程序域。 要创建新的AppDomain并将程序集加载到其中,请执行以下操作:

    public void TempLoadAssembly()
    {
        AppDomain tempDomain = AppDomain.CreateDomain("TemporaryAppDomain");
        tempDomain.DoCallBack(LoaderCallback);
        AppDomain.Unload(tempDomain);
    }
    
    private void LoaderCallback()
    {
        Assembly.ReflectionOnlyLoad("YourAssembly");
        // Do your stuff here
    }
    
        2
  •  9
  •   Drew Noakes    15 年前

    虽然不是真正的卸载程序集,但如果您只是试图获取可以使用的文件的版本号 System.Diagnostics.FileVersionInfo .

    var info = FileVersionInfo.GetVersionInfo(path);
    

    FileVersionInfo 具有以下属性:

    public string Comments { get; }
    public string CompanyName { get; }
    public int FileBuildPart { get; }
    public string FileDescription { get; }
    public int FileMajorPart { get; }
    public int FileMinorPart { get; }
    public string FileName { get; }
    public int FilePrivatePart { get; }
    public string FileVersion { get; }
    public string InternalName { get; }
    public bool IsDebug { get; }
    public bool IsPatched { get; }
    public bool IsPreRelease { get; }
    public bool IsPrivateBuild { get; }
    public bool IsSpecialBuild { get; }
    public string Language { get; }
    public string LegalCopyright { get; }
    public string LegalTrademarks { get; }
    public string OriginalFilename { get; }
    public string PrivateBuild { get; }
    public int ProductBuildPart { get; }
    public int ProductMajorPart { get; }
    public int ProductMinorPart { get; }
    public string ProductName { get; }
    public int ProductPrivatePart { get; }
    public string ProductVersion { get; }
    public string SpecialBuild { get; }
    
        3
  •  4
  •   Ilya Ryzhenkov    16 年前

    你可以试着用 Unmanaged Metadata API 它是COM,可以很容易地从.NET应用程序使用某种包装器。

        4
  •  3
  •   Albert    16 年前

    您必须使用应用程序域,没有其他方法卸载程序集。基本上你必须使用这样的代码:

    AppDomain tempDomain = AppDomain.CreateDomain("Temp Domain");
    tempDomain.Load(assembly);
    AppDomain.Unload(tempDomain);
    
    
        5
  •  2
  •   Artiom    8 年前

    您可以在新的AppDomain中创建一个实例,并在该实例中执行代码。

    var settings = new AppDomainSetup
    {
        ApplicationBase = AppDomain.CurrentDomain.BaseDirectory,
    };
    var childDomain = AppDomain.CreateDomain(Guid.NewGuid().ToString(), null, settings);
    
     var handle = Activator.CreateInstance(childDomain,
                typeof(ReferenceLoader).Assembly.FullName,
                typeof(ReferenceLoader).FullName,
                false, BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance, null, null, CultureInfo.CurrentCulture, new object[0]);
    
    
    var loader = (ReferenceLoader)handle.Unwrap();
    
    //This operation is executed in the new AppDomain
    var paths = loader.LoadReferences(assemblyPath);
    
    
    AppDomain.Unload(childDomain);
    

    这是引用加载程序

    public class ReferenceLoader : MarshalByRefObject
    {
        public string[] LoadReferences(string assemblyPath)
        {
            var assembly = Assembly.ReflectionOnlyLoadFrom(assemblyPath);
            var paths = assembly.GetReferencedAssemblies().Select(x => x.FullName).ToArray();
            return paths;
        }
    }