2008-09-23 29 views
38

Tôi muốn biết cách dỡ một assembly được nạp vào AppDomain chính.Làm thế nào để dỡ bỏ một assembly từ AppDomain chính?

Tôi có đoạn mã sau:

var assembly = Assembly.LoadFrom(FilePathHere); 

tôi cần/muốn để có thể dỡ bỏ assembly này khi tôi đang thực hiện.

Cảm ơn sự giúp đỡ của bạn.

+1

Cố gắng không sử dụng LoadFrom, nó ở trong một ngữ cảnh khác với ngữ cảnh tải và có thể gây ra vấn đề. – user7116

+0

Câu hỏi hay nhưng tôi không thể thấy bất kỳ câu trả lời R CLE RÀNG về cách giải quyết var assembly = Assembly.LoadFrom (FilePathHere); –

Trả lời

32

Bạn không thể tải xuống một assembly từ một appdomain. Bạn có thể phá hủy các appdomain, nhưng khi một assembly được nạp vào appdomain, nó sẽ có trong cuộc đời của appdomain.

giải thích Xem Jason Zander của Why isn't there an Assembly.Unload method?

Nếu bạn đang sử dụng 3.5, bạn có thể sử dụng khung AddIn để làm cho nó dễ dàng hơn để quản lý/gọi vào AppDomains khác nhau (mà bạn thể dỡ bỏ, dỡ tất cả các hội đồng) . Nếu bạn đang sử dụng các phiên bản trước đó, bạn cần tự tạo một appdomain mới để dỡ bỏ nó.

+0

Tôi nghĩ điều này đã thay đổi với .Net 3.5? –

+1

Không có kế hoạch để cho phép dỡ bỏ một hội đồng từ một miền ứng dụng (tôi sẽ không mong đợi họ hoặc là, nó là rất khó để làm và những người chăm sóc sẽ sử dụng một cách an toàn hơn và sạch hơn). Điều tốt nhất bạn có thể làm là gen mã nhẹ mà Khoth đã đề cập đến – ShuggyCoUk

14

Bạn không thể dỡ tải một hội đồng mà không phải dỡ toàn bộ AppDomain. Here's why:

  1. Bạn đang chạy mã trong lĩnh vực ứng dụng. Điều đó có nghĩa là có khả năng gọi các trang web và gọi ngăn xếp với các địa chỉ trong đó đang mong đợi để tiếp tục làm việc.

  2. Giả sử bạn đã quản lý để theo dõi tất cả các xử lý và tham chiếu đến mã đang chạy bởi một hội đồng. Giả sử bạn không nguyền rủa mã, khi bạn đã giải phóng thành công hội đồng, bạn chỉ giải phóng siêu dữ liệu và IL. Mã JIT'd vẫn được cấp phát trong bộ nạp miền ứng dụng (các phương thức JIT'd được phân bổ tuần tự trong một bộ đệm theo thứ tự mà chúng được gọi).

  3. Vấn đề cuối cùng liên quan đến mã đã được tải chia sẻ, nếu không chính thức hơn được gọi là "miền trung lập" (hãy kiểm tra/chia sẻ trên công cụ ngen). Trong chế độ này, mã cho một hội đồng được tạo ra để được thực hiện từ bất kỳ miền ứng dụng nào (không có gì khó có dây).

Chúng tôi khuyên bạn nên thiết kế ứng dụng của mình xung quanh ranh giới miền ứng dụng một cách tự nhiên, tại đó dỡ hoàn toàn được hỗ trợ.

4

Nếu bạn muốn có mã tạm thời có thể được tải xuống sau đó, tùy thuộc vào nhu cầu của bạn, lớp DynamicMethod có thể làm những gì bạn muốn. Điều đó không cung cấp cho bạn các lớp học, mặc dù.

8

Bạn nên tải các cụm tạm thời của mình vào AppDomain khác và khi không sử dụng thì bạn có thể tải xuống AppDomain đó. Nó an toàn và nhanh chóng.

+2

Xem AppDomain.DoCallback và cũng xem MarshalByRefObject: bạn tạo ra một MarshalByRefObject "invoker" với một phương thức làm những gì bạn muốn và trả về một cái gì đó trong các trường có thể thay đổi của nó, bạn tạo một AppDomain tạm thời và gọi dom.DoCallback (invoker.DoSomething) để làm cho đối tượng này làm những gì bạn muốn; sau đó bạn thu thập các kết quả từ người invoker trong appdomain của bạn và dỡ bỏ tên miền tạm thời. – jkff

+0

@jkff: Thật không may nếu bạn sử dụng MarshalByRefObject, như trong ví dụ PingPong, Assembly.LoadFrom sẽ thực thi như thể trong AppDomain chính, vì vậy việc dỡ bỏ tạm thời AppDomain vẫn sẽ mang lại vấn đề cũ là không thể dỡ bỏ assembly. Tôi nghĩ rằng bạn có thể phải bằng cách nào đó serialize dữ liệu bạn muốn từ AppDomain tạm thời, mà không marshaling, nếu bạn muốn truy cập nó và vẫn có thể dỡ bỏ lắp ráp. – user420667

+0

@jkff: Bạn có thể đúng mặc dù ... nhưng nó không đơn giản như những gì được mô tả trong ví dụ MSDN. Một có lẽ nên sử dụng tempAppDomain.CreateInstanceAndUnwrap ... và nó có thể cần thiết ngay cả khi sử dụng AppDomain.GetData và SetData. (Điều này sẽ không thực sự lộn xộn appdomain nếu nó chỉ là mục đích là để được nạp và unloaded.) – user420667

0

Tôi biết cũ của nó nhưng có thể giúp đỡ một ai đó. Bạn có thể tải tệp từ luồng và phát hành tệp. Nó làm việc cho tôi. Tôi đã tìm thấy giải pháp HERE.

Hy vọng điều đó sẽ hữu ích.

13

Tôi cũng biết điều này rất cũ, nhưng có thể giúp ai đó gặp sự cố này! Đây là một cách tôi đã tìm thấy để làm điều đó! thay vì sử dụng:

var assembly = Assembly.LoadFrom(FilePathHere); 

sử dụng này:

var assembly = Assembly.Load(File.ReadAllBytes(FilePathHere)); 

Điều này thực sự tải "Nội dung" của file lắp ráp, thay vì các tập tin riêng của mình. Điều đó có nghĩa là KHÔNG có khóa tập tin được đặt trên tập tin lắp ráp! Vì vậy, bây giờ nó có thể được sao chép, xóa hoặc nâng cấp mà không đóng ứng dụng của bạn hoặc cố gắng sử dụng một AppDomain riêng biệt hoặc Marshaling!

PROS: Rất đơn giản để khắc phục bằng 1 Lót mã! Nhược điểm: Không thể sử dụng AppDomain, Assembly.Location hoặc Assembly.CodeBase.

Bây giờ bạn chỉ cần hủy mọi phiên bản được tạo trên assembly. Ví dụ:

assembly = null; 
+0

Bởi "** Không thể sử dụng AppDomain **" bạn có nghĩa là bạn không thể bắt đầu một bên trong hội đồng đó hoặc bạn có thể cụ thể hơn ? Điều gì về 'AppDomain.CurrentDomain.Load (File.ReadAllBytes (FilePathHere));' là có bất kỳ sự khác biệt thực sự từ Assembly.Load trong kịch bản cụ thể này? – Prix

0

Là một thay thế, nếu lắp ráp đã được chỉ nạp ở nơi đầu tiên, để kiểm tra thông tin của các hội đồng như PublicKey, cách tốt hơn là nên không tải nó, và thay vì kiểm tra thông tin bằng cách tải chỉ AssemblyName lúc đầu tiên:

AssemblyName an = AssemblyName.GetAssemblyName ("myfile.exe"); 
byte[] publicKey = an.GetPublicKey(); 
CultureInfo culture = an.CultureInfo; 
Version version = an.Version; 
Các vấn đề liên quan