代码之家  ›  专栏  ›  技术社区  ›  Josh Smeaton

在.NET中动态加载程序集时出现问题

  •  6
  • Josh Smeaton  · 技术社区  · 14 年前

    我们构建了一个小组件,它获取一个ID,在数据库中查找程序集/命名空间/类的条目,并动态加载我们所追求的类的实例。到目前为止,它一直工作得很好,但是在Vs2010中运行此代码时,它失败了。

    Private Function AssemblyLoaded(ByVal assemblyFile As String) As Assembly
        Dim assemblies() As Assembly = AppDomain.CurrentDomain.GetAssemblies
    
        For Each asmb As Assembly In assemblies
            If (asmb.Location = assemblyFile)) Then Return asmb
        Next
        Return Nothing
    End Function
    

    第一个问题是,当迭代器命中动态程序集时,没有asmb.location,并且抛出了NotSupportedException。是否有任何方法可以在不捕获异常的情况下检查位置字段是否不受支持?

    第二个问题asmb.location返回的是整个路径,而不仅仅是文件名,这意味着这个函数每次都会失败。如果此函数确定某个类尚未加载,那么我们将尝试加载它并获取一个AccessViolationException,因为该类已加载,我们无法“重新加载”它。

    将功能更改为此工作:

    Private Function AssemblyLoaded(ByVal assemblyFile As String) As Assembly
        Dim assemblies() As Assembly = AppDomain.CurrentDomain.GetAssemblies
    
        For Each asmb As Assembly In assemblies
            Try
                If (asmb.Location.EndsWith(assemblyFile)) Then Return asmb
            Catch ex As NotSupportedException
                Continue For
            End Try
        Next
    
        Return Nothing
    End Function
    

    但感觉很脏。是否有更好的方法检查程序集是否已加载,并将其返回给调用方?以上问题是否特定于.NET 4.0或Visual Studio 2010?我没有在IDE之外尝试过,因为它需要相当重要的配置。

    3 回复  |  直到 8 年前
        1
  •  5
  •   Hans Passant    14 年前

    可以通过跳过assemblybuilder实例来检查程序集是否是动态的。应该使用path.getFileName()来隔离名称。注意,这不是一个好主意,因为来自不同路径的程序集可能具有相同的名称。但你似乎被这个困住了。因此:

    Private Function AssemblyLoaded(ByVal assemblyFile As String) As Assembly
        For Each asmb As Assembly In AppDomain.CurrentDomain.GetAssemblies
            If TypeOf asmb Is System.Reflection.Emit.AssemblyBuilder Then Continue For
            If System.IO.Path.GetFileName(asmb.Location) = assemblyFile Then Return asmb
        Next
        Return Nothing
    End Function
    

    或许,案件敏感性也是你应该处理的问题。

        2
  •  2
  •   Daniel Wolf deepee1    13 年前

    添加到HansPassant的anwer中:对于我的应用程序(C 4.0),跳过 AssemblyBuilder 还是失败了。原来还有一个班, System.Reflection.Emit.InternalAssemblyBuilder ,也会抛出一个 NotSupportedException 当访问时 Location .

    InternalAssemblyBuilder RuntimeAssembly (所需的类型)都是内部的,所以我能想到的最好的方法是(在C)中:

    var assemblies = AppDomain.CurrentDomain
        .GetAssemblies()
        .Where(assembly => assembly.GetType().Name == "RuntimeAssembly")
        .Select(assembly => assembly.Location)
        .ToArray();
    
        3
  •  0
  •   Denis Troller    8 年前

    如果使用.NET 4.0,则应检查 Assembly.IsDynamic 它覆盖了所有的基地…