2010-05-24 17 views
6

Chúng ta đã xây dựng một thành phần nhỏ có một Id, tra cứu một mục trong cơ sở dữ liệu cho một assembly/namespace/class và tự động nạp một thể hiện của lớp mà chúng ta sau. Nó đã được làm việc tốt cho đến bây giờ, nhưng khi chạy mã này trong VS 2010, nó không thành công.Vấn đề với việc nạp linh hoạt các assembly trong .NET

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 

Vấn đề đầu tiên là, khi iterator lượt truy cập một hội động, không có asmb.Location, và một NotSupportedException được ném. Có cách nào để kiểm tra tính không được hỗ trợ của trường Vị trí mà không phải bắt ngoại lệ không?

Vấn đề thứ hai, asmb.Location đang trả lại toàn bộ đường dẫn thay vì chỉ tên tệp, có nghĩa là chức năng này không thành công mỗi lần. Nếu hàm này xác định rằng một lớp chưa được nạp, thì chúng ta sẽ thử tải nó và nhận một AccessViolationException vì lớp đã nạp và chúng ta không thể "nạp lại" nó.

Thay đổi chức năng để làm việc này:

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 

Nhưng nó cảm thấy bẩn. Có cách nào tốt hơn để kiểm tra xem một hội đồng đã được tải chưa và chuyển lại cho người gọi chưa? Các vấn đề trên cụ thể với .NET 4.0 hoặc Visual Studio 2010? Tôi đã không cố gắng này bên ngoài IDE vì nó đòi hỏi cấu hình khá đáng kể.

Trả lời

5

Bạn có thể kiểm tra xem lắp ráp có động không bằng cách bỏ qua các phiên bản của AssemblyBuilder. Bạn nên sử dụng Path.GetFileName() để cô lập tên. Hãy coi chừng rằng đây không phải là một ý tưởng rất tốt vì các hội đồng từ các đường dẫn khác nhau có thể có tên giống nhau. Nhưng bạn dường như bị mắc kẹt với điều này. Do đó:

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 

Độ nhạy trường hợp là điều bạn nên đối phó, có lẽ.

+0

Công trình này, cảm ơn bạn. Tôi loại bỏ các. ToLower cho ngắn gọn, nhưng chúng tôi đối phó với trường hợp nhạy cảm. –

2

Để thêm vào anwer Hans Passant: cho ứng dụng của tôi (C# 4.0), bỏ qua trường hợp AssemblyBuilder vẫn không thành công. Hóa ra có một lớp khác, System.Reflection.Emit.InternalAssemblyBuilder, cũng ném một số NotSupportedException khi truy cập Location.

InternalAssemblyBuilderRuntimeAssembly (kiểu như mong muốn) đều nội bộ, vì vậy tốt nhất tôi có thể đưa ra là (trong C#):

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

Nếu bạn đang sử dụng .Net 4.0, bạn nên kiểm tra Assembly.IsDynamic, bao gồm tất cả các căn cứ –

+0

@DenisTroller cảm ơn cho nhận xét đó - bạn thực sự nên để nó như một câu trả lời :) – Jedidja

0

Nếu bạn đang sử dụng Net 4.0, bạn nên kiểm tra Assembly.IsDynamic, bao gồm tất cả các căn cứ ...

Các vấn đề liên quan