我们构建了一个小组件,它接受一个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
第一个问题是,当迭代器命中动态程序集时,没有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外面尝试这个,因为它需要相当重要的配置。
答案 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
。
InternalAssemblyBuilder
和RuntimeAssembly
(所需的类型)都是内部的,所以我能想到的最好的是(在C#中):
var assemblies = AppDomain.CurrentDomain
.GetAssemblies()
.Where(assembly => assembly.GetType().Name == "RuntimeAssembly")
.Select(assembly => assembly.Location)
.ToArray();
答案 2 :(得分:0)
如果您使用的是.Net 4.0,则应检查Assembly.IsDynamic,其中包含所有基础......