2012-05-03 27 views
10

hiện tại Tôi đã tạo một ứng dụng nhỏ để đệ quy tải các assembly trong một thư mục được cung cấp và đọc các thuộc tính tùy chỉnh của chúng. Chủ yếu chỉ để đọc DebuggableAttribute để xác định các thiết lập cho IsJITTrackingEnabled và IsJITOptimizerDisabled để xác định xem assembly có được tối ưu hóa để phát hành hay không.Lấy các thuộc tính assembly tùy chỉnh mà không tải vào AppDomain

Mã hiện tại của tôi thực hiện Assembly.LoadFrom để chuyển toàn bộ đường dẫn đến assembly và tải nó. Sau đó, một GetCustomAttributes trên lắp ráp để có được các thuộc tính debuggable. Vấn đề là mỗi assembly được nạp vào appdomain hiện tại. Vì vậy, nếu một thư mục khác sử dụng cùng một assembly, nó chỉ sử dụng tham chiếu được nạp ban đầu. Tôi muốn để có thể tải lắp ráp, đọc các thuộc tính tôi cần, sau đó dỡ bỏ nó. Tôi đã cố gắng tạo ra một appdomain mới và tải các hội đồng vào nó sau đó dỡ bỏ các afterword lắp ráp vô ích.

Tôi biết điều này phải có thể nhưng tôi thua lỗ. Mọi sự trợ giúp sẽ rất được trân trọng. Tôi rất sẵn lòng cung cấp bất kỳ thông tin nào khác mà bạn có thể cần.

Trả lời

17

Câu trả lời ngắn gọn là, không, không có cách nào để làm những gì bạn đang yêu cầu.

Câu trả lời dài hơn là: Có phương pháp tải lắp ráp đặc biệt, Assembly.ReflectionOnlyLoad(), sử dụng ngữ cảnh tải "chỉ phản chiếu". Điều này cho phép bạn tải các assembly không thể thực hiện được, nhưng có thể đọc siêu dữ liệu của chúng.

Trong trường hợp của bạn (và, rõ ràng, trong mọi trường hợp sử dụng, tôi có thể tự tìm ra) nó không thực sự hữu ích. Bạn không thể nhận được thuộc tính đã nhập từ loại lắp ráp này, chỉ CustomAttributeData. Lớp đó không cung cấp bất kỳ cách nào tốt để lọc cho một thuộc tính cụ thể (tốt nhất tôi có thể đưa ra là đưa nó vào một chuỗi và sử dụng StartsWith("[System.Diagnostics.Debuggable");

Thậm chí tệ hơn, tải chỉ phản ánh không tải bất kỳ phụ thuộc nào hội đồng, nhưng nó buộc bạn phải làm điều đó theo cách thủ công. Điều đó làm cho nó trở nên khách quan tồi tệ hơn những gì bạn đang làm bây giờ, ít nhất bây giờ bạn nhận được sự phụ thuộc tải tự động. Tôi đã sai, có vẻ như MEF bao gồm toàn bộ tấn mã phản chiếu tùy chỉnh để thực hiện công việc này.)

Cuối cùng, bạn không thể mở oad một hội đồng một khi nó đã được nạp. Bạn cần phải dỡ bỏ các toàn bộ miền ứng dụng, như mô tả trong this MSDN article.

UPDATE:

Như đã đề cập trong các ý kiến, tôi đã có thể để có được những thông tin thuộc tính bạn cần thông qua tải phản ánh chỉ (và một tải bình thường) nhưng thiếu siêu dữ liệu thuộc tính đã nhập làm cho nó trở thành một nỗi đau nghiêm trọng.

Nếu nạp vào một bối cảnh hội bình thường, bạn có thể nhận được thông tin bạn cần một cách dễ dàng đủ:

var d = a.GetCustomAttributes(typeof(DebuggableAttribute), false) as DebuggableAttribute; 
var tracking = d.IsJITTrackingEnabled; 
var optimized = !d.IsJITOptimizerDisabled; 

Nếu nạp vào một bối cảnh suy-only, bạn có thể làm một số công việc; bạn phải tìm ra biểu mẫu mà hàm tạo thuộc tính đã lấy, biết giá trị mặc định là gì và kết hợp thông tin đó để tìm ra các giá trị cuối cùng của mỗi thuộc tính.Bạn nhận được các thông tin cần thiết như thế này:

var d2 = a.GetCustomAttributesData() 
     .SingleOrDefault(x => x.ToString() 
           .StartsWith("[System.Diagnostics.DebuggableAttribute")); 

Từ đó, bạn cần phải kiểm tra các ConstructorArguments để xem những constructor được gọi là: this one với một đối số hoặc this one với hai đối số. Sau đó bạn có thể sử dụng các giá trị của các thông số thích hợp để tìm ra những giá trị hai thuộc tính bạn quan tâm đã có thể lấy:

if (d2.ConstructorArguments.Count == 1) 
{ 
    var mode = d2.ConstructorArguments[0].Value as DebuggableAttribute.DebuggingModes; 
    // Parse the modes enumeration and figure out the values. 
} 
else 
{ 
    var tracking = (bool)d2.ConstructorArguments[0].Value; 
    var optimized = !((bool)d2.ConstructorArguments[1].Value); 
} 

Cuối cùng, bạn cần phải kiểm tra cho NamedArguments có thể ghi đè lên những thiết lập trên các nhà xây dựng, sử dụng ví dụ:

var arg = NamedArguments.SingleOrDefault(x => x.MemberInfo.Name.Equals("IsJITOptimizerDisabled")); 
var optimized = (arg == null || !((bool)arg.TypedValue.Value)); 

một lưu ý cuối cùng, nếu bạn đang chạy này dưới NET 2.0 hoặc cao hơn, và chưa thấy trong, MSDN điểm này ra trong tài liệu DebuggingModes:

Trong .NET Framework phiên bản 2.0, thông tin theo dõi JIT luôn được tạo và cờ này có tác dụng tương tự như Mặc định ngoại trừ thuộc tính IsJITTrackingEnabled là sai, không có ý nghĩa trong phiên bản 2.0.

+0

Điểm tốt về việc dỡ hàng! –

+0

Cảm ơn bạn. Tôi đã thử điều đó nhưng gặp khó khăn khi truy cập IsJITTrackingEnabled và IsJITOptimizerDisabled thông qua đối tượng CustomAttributeData. Tôi có nói về điều đó không chính xác không? – RockyMountainHigh

+0

Vâng, tôi đã có thể làm những gì bạn muốn nhưng tôi cũng phát hiện ra rằng 'ReflectionOnlyLoad' cơ bản là vô dụng. Nó không tự động tải phụ thuộc - * bạn phải tự tải chúng *. (Tôi cũng phát hiện ra rằng MEF đã thực hiện một bối cảnh phản chiếu tùy chỉnh và dường như không sử dụng điều này chút nào.) –

0

Tôi tin Assembly.ReflectionOnlyLoad là những gì bạn đang tìm kiếm.

9

Bạn cần sử dụng Assembly.ReflectionOnlyLoad.

Dưới đây là một số MSDN Notes cho thấy làm thế nào để sử dụng nó:

using System; 
using System.IO; 
using System.Reflection; 

public class ReflectionOnlyLoadTest 
{ 
    public ReflectionOnlyLoadTest(String rootAssembly) { 
     m_rootAssembly = rootAssembly; 
    } 

    public static void Main(String[] args) 
    { 
     if (args.Length != 1) { 
      Console.WriteLine("Usage: Test assemblyPath"); 
      return; 
     } 

     try { 
      ReflectionOnlyLoadTest rolt = new ReflectionOnlyLoadTest(args[0]); 
      rolt.Run(); 
     } 

     catch (Exception e) { 
      Console.WriteLine("Exception: {0}!!!", e.Message); 
     } 
    } 

    internal void Run() { 
     AppDomain curDomain = AppDomain.CurrentDomain; 
     curDomain.ReflectionOnlyPreBindAssemblyResolve += new ResolveEventHandler(MyReflectionOnlyResolveEventHandler); 
     Assembly asm = Assembly.ReflectionOnlyLoadFrom(m_rootAssembly); 

     // force loading all the dependencies 
     Type[] types = asm.GetTypes(); 

     // show reflection only assemblies in current appdomain 
     Console.WriteLine("------------- Inspection Context --------------"); 
     foreach (Assembly a in curDomain.ReflectionOnlyGetAssemblies()) 
     { 
      Console.WriteLine("Assembly Location: {0}", a.Location); 
      Console.WriteLine("Assembly Name: {0}", a.FullName); 
      Console.WriteLine(); 
     } 
    } 

    private Assembly MyReflectionOnlyResolveEventHandler(object sender, ResolveEventArgs args) { 
     AssemblyName name = new AssemblyName(args.Name); 
     String asmToCheck = Path.GetDirectoryName(m_rootAssembly) + "\\" + name.Name + ".dll"; 
     if (File.Exists(asmToCheck)) { 
      return Assembly.ReflectionOnlyLoadFrom(asmToCheck); 
     } 
     return Assembly.ReflectionOnlyLoad(args.Name); 
    } 

    private String m_rootAssembly; 
} 
4

Nó không thể bao giờ dỡ bỏ một hội trong AppDomain hiện tại, mà chỉ là cách .NET được thiết kế để làm việc không may. Điều này thậm chí là trường hợp với ReflectionOnly tải. Ngoài ra còn có một chút nhăn với làm điều đó cũng như sau đó bạn cần phải sử dụng phương pháp GetCustomAttributesData thay vì GetCustomAttributes bình thường như sau này cần phải chạy mã trong constructor thuộc tính. Điều này có thể làm cho cuộc sống trở nên khó khăn hơn.

Phương án thay thế sẽ hoạt động là sử dụng Cecil cho phép bạn kiểm tra lắp ráp mà không thực sự tải nó theo nghĩa thông thường. Nhưng đó là rất nhiều công việc phụ.

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