【问题标题】:Get Assemblies Without Instantiating Them获取程序集而不实例化它们
【发布时间】:2012-04-14 10:16:46
【问题描述】:

我正在尝试使用 AppDomain.CurrentDomain.GetAssemblies()FullName 写入 DropDownList 中的所有程序集 CurrentDomain,但是如果我不实例化它们,它们不会出现在来自 GetAssemblies() 的返回数组中在CurrentDomain

它们都作为参考添加到解决方案的Reference 文件夹中。只有当我第一次实例化它们时,我才能从 GetAssemblies() 获取它们。

当我添加新的程序集等时,如何用一种简单且更通用的方式来解决这个问题,而不是每次都实例化它们。

由于公司政策,我必须对图像的某些部分进行模糊处理:

所有程序集都在 Reference 文件夹中引用:

【问题讨论】:

    标签: c# .net vb.net assemblies


    【解决方案1】:

    在您实例化类型或依赖类型之前,它们不会被加载。因此,如果您的项目引用了大量程序集,但没有实例化其中的任何类型,则您的应用不会因从磁盘加载这些位而产生性能损失。

    如果您想找出您的项目引用了哪些程序集,您必须使用.NET Reflection 探索您的程序集。具体来说,我建议你看看Assembly.GetReferencedAssemblies()方法。

    HTH。

    【讨论】:

    • 我找到了一个自动为我做的快速答案。
    • @Braveyard:什么意思?
    【解决方案2】:

    这就是我所做的和为我工作的:

    Private Sub Pre_Load()
        Dim sBasePath As String = AppDomain.CurrentDomain.BaseDirectory
        Dim sAllFiles() As String = Directory.GetFiles(sBasePath)
        For Each sAssemblyFile As String In sAllFiles
            If sAssemblyFile.EndsWith(".dll") Then
                If Not Me.HasThisAssembly(sAssemblyFile) Then
                    Assembly.Load(AssemblyName.GetAssemblyName(sAssemblyFile))
                End If
            End If
        Next
    End Sub
    
    Private Function HasThisAssembly(ByVal vsAssemblyName As String) As Boolean
        For Each oAssembly As Assembly In AppDomain.CurrentDomain.GetAssemblies()
            Dim oFile As New FileInfo(vsAssemblyName)
            If oFile.Name = oAssembly.GetName().Name + ".dll" Then
                Return True
                Exit Function
            End If
        Next
        Return False
    End Function
    

    【讨论】:

    • 标记下来有两个原因:1) Pre_Load 仅在当前应用程序域的文件夹中查找程序集文件。不考虑 CLR 加载程序的递归程序集查找,也不考虑 GAC 中的程序集。 2) HasThisAssembly 只查找当前加载的程序集——这正是 OP 想要避免的。简而言之,此解决方案不会枚举引用的程序集——无论它们是否在本地可用或在 GAC 中。
    • @RichardTurner 虽然我同意这并不能真正回答问题,但这个回答者 OP,所以我不会-1!
    【解决方案3】:

    除了其他人的cmets之外,这里实际上还发生了一些微妙的事情。

    VisualStudio 实际上将 .dll 引用添加到您构建的程序集的反射信息的程序集清单中,除非它们被实际使用。

    作为示例,创建一个新项目并引用一个程序集。我以nunit.framework.dll 为例。

    但实际上不要使用它。我的代码很简单:

    namespace ConsoleApplication1
    {
        class Program
        {
            static void Main(string[] args)
            {
            }
        }
    }
    

    但项目确实在 VisualStudio 中有对 NUnit 的引用。现在构建它,并在ildasm.exe 中打开程序集,清单的顶部是:

    // Metadata version: v4.0.30319
    .assembly extern mscorlib
    {
      .publickeytoken = (B7 7A 5C 56 19 34 E0 89 )                         // .z\V.4..
      .ver 4:0:0:0
    }
    .assembly ConsoleApplication1
    {
        ...etc...
    

    现在,在代码中,只需使用 NUnit 中的任何内容:

    namespace ConsoleApplication1
    {
        class Program
        {
            static void Main(string[] args)
            {
                Assert.IsTrue(true);
            }
        }
    }
    

    再次重建并检查ildasm.exe 中的程序集清单:

    // Metadata version: v4.0.30319
    .assembly extern mscorlib
    {
      .publickeytoken = (B7 7A 5C 56 19 34 E0 89 )                         // .z\V.4..
      .ver 4:0:0:0
    }
    .assembly extern nunit.framework
    {
      .publickeytoken = (96 D0 9A 1E B7 F4 4A 77 )                         // ......Jw
      .ver 2:6:0:12051
    }
    .assembly ConsoleApplication1
    {
        ...etc...
    

    请注意,现在 IL 中有一个 extern。这也提供反射,因此它知道要加载哪些依赖程序集。

    除此之外,正如其他人所说,运行时实际上不会加载程序集,直到第一次需要它,因此您的 AppDomain 没有加载程序集,直到您实例化或使用该程序集中的某些东西.


    当您开始尝试使用Assembly.GetReferencedAssemblies() 方法时,上述细节就会发挥作用。

    所以在 VisualStudio 中,我有一个包含这些引用的项目:

    Microsoft.CSharp
    nunit.framework
    System
    System.Core
    System.Data
    System.Xml
    System.Xml.Linq
    

    然后我有 C# 代码:

    using System;
    using System.Reflection;
    using NUnit.Framework;
    
    namespace ConsoleApplication1
    {
        class Program
        {
            static void Main(string[] args)
            {
                var assemblies = Assembly.GetExecutingAssembly().GetReferencedAssemblies();
                foreach (var assemblyName in assemblies)
                {
                    Console.WriteLine(assemblyName.FullName);
                }
                Console.ReadKey();
            }
        }
    }
    

    请注意,我什至有 using NUnit.Framework; 声明!但我实际上并没有在任何地方使用 NUnit,所以它不是一个被引用的程序集。运行这个的输出是:

    mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
    

    就是这样。 如果我将此行添加到我的测试应用程序中:

    Assert.IsTrue(true);
    

    现在有些东西实际上使用 NUnit,而我的控制台输出是:

    mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
    nunit.framework, Version=2.6.0.12051, Culture=neutral, PublicKeyToken=96d09a1eb7f44a77
    

    【讨论】:

    • 对不起,如果我的帖子的意图不明确,但我试图表明在 VisualStudio 中显示作为引用添加的内容是没有意义的。它更多的是用于编译器,并且对实际放入程序集中的内容几乎没有影响。
    • +1 以获得清晰、彻底的答案 :) 我将其留给 OP 来了解这些事实 ;)
    猜你喜欢
    • 2017-12-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-09-20
    • 2023-03-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多