【问题标题】:Problem with dynamically loading assemblies in .NET在 .NET 中动态加载程序集的问题
【发布时间】:2010-05-24 07:32:03
【问题描述】:

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

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

第一个问题是,当迭代器碰到一个Dynamic Assembly时,没有asmb.Location,会抛出一个NotSupportedException。有什么方法可以检查 Location 字段的 Unsupported-ness 而不必捕获异常?

第二个问题,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 之外尝试过这个,因为它需要相当多的配置。

【问题讨论】:

    标签: c# vb.net visual-studio reflection .net-4.0


    【解决方案1】:

    您可以通过跳过 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
    

    也许你也应该处理区分大小写的问题。

    【讨论】:

    • 这行得通,谢谢。为简洁起见,我删除了 .ToLower,但我们会处理区分大小写的问题。
    【解决方案2】:

    补充 Hans Passant 的答案:对于我的应用程序 (C# 4.0),跳过 AssemblyBuilder 的实例仍然失败。原来还有另一个类System.Reflection.Emit.InternalAssemblyBuilder,在访问Location 时也会抛出NotSupportedException

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

    var assemblies = AppDomain.CurrentDomain
        .GetAssemblies()
        .Where(assembly => assembly.GetType().Name == "RuntimeAssembly")
        .Select(assembly => assembly.Location)
        .ToArray();
    

    【讨论】:

    • 如果你使用.Net 4.0,你应该检查Assembly.IsDynamic,它涵盖了所有的基础
    • @DenisTroller 感谢您的评论-您真的应该将其作为答案:)
    【解决方案3】:

    如果你使用.Net 4.0,你应该检查Assembly.IsDynamic,它涵盖了所有的基础......

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-10-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-02-23
      相关资源
      最近更新 更多