在.NET中动态加载程序集的问题

时间:2010-05-24 07:32:03

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

我们构建了一个小组件,它接受一个I​​d,在数据库中查找一个程序集/命名空间/类的条目,并动态加载我们所追求的类的实例。到目前为止它一直很好用,但是在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

第一个问题是,当迭代器命中动态程序集时,没有asmb.Location,并抛出NotSupportedException。有没有办法检查位置字段的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外面尝试这个,因为它需要相当重要的配置。

3 个答案:

答案 0 :(得分:5)

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

也许你应该处理区分大小写的事情。

答案 1 :(得分:2)

添加到Hans Passant的anwer:对于我的应用程序(C#4.0),跳过AssemblyBuilder的实例仍然失败。结果还有另一个类System.Reflection.Emit.InternalAssemblyBuilder,在访问NotSupportedException时也会引发Location

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

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

答案 2 :(得分:0)

如果您使用的是.Net 4.0,则应检查Assembly.IsDynamic,其中包含所有基础......