1. Trang chủ >
  2. Công Nghệ Thông Tin >
  3. Kỹ thuật lập trình >

7 Thể hiện hóa một kiểu trong miền ứng dụng khác

Bạn đang xem bản rút gọn của tài liệu. Xem và tải ngay bản đầy đủ của tài liệu tại đây (4.45 MB, 563 trang )


81

Chương 3: Miền ứng dụng, cơ chế phản chiếu, và siêu dữ liệu







Gọi phương thức CreateInstance hay CreateInstanceFrom của đối tượng AppDomain

đại diện cho miền ứng dụng đích.



Việc sử dụng phương thức ExecuteAssembly (đã được thảo luận trong mục 3.6) không mấy

khó khăn; nhưng khi phát triển các ứng dụng phức tạp có sử dụng nhiều miền ứng dụng, chắc

chắn bạn muốn kiểm soát quá trình nạp các assembly, tạo các kiểu dữ liệu, và triệu gọi các

thành viên của đối tượng bên trong miền ứng dụng.

Các phương thức CreateInstance và CreateInstanceFrom cung cấp nhiều phiên bản nạp

chồng giúp bạn kiểm soát quá trình tạo đối tượng. Các phiên bản đơn giản nhất sử dụng

phương thức khởi dựng mặc định của kiểu, nhưng cả hai phương thức này đều thiết đặt các

phiên bản cho phép bạn cung cấp đối số để sử dụng bất kỳ phương thức khởi dựng nào.

Phương thức CreateInstance nạp một assembly có tên xác định vào miền ứng dụng bằng quá

trình đã được mô tả cho phương thức Assembly.Load trong mục 3.5. Sau đó, CreateInstance

tạo đối tượng cho kiểu và trả về một tham chiếu đến đối tượng mới được đóng gói trong

ObjectHandle (được mô tả trong mục 3.3). Tương tự như thế đối với phương thức

CreateInstanceFrom; tuy nhiên, CreateInstanceFrom nạp assembly vào miền ứng dụng bằng

quá trình đã được mô tả cho phương thức Assembly.LoadFrom trong mục 3.5.







AppDomain



cũng



cung



cấp



hai



phương



thức



rất



tiện



lợi







tên







CreateInstanceAndUnwrap và CreateInstanceFromAndUnwrap, chúng sẽ tự động khôi



phục tham chiếu đến đối tượng đã được tạo từ đối tượng ObjectHandle; bạn phải

ép đối tượng trả về cho đúng kiểu trước khi sử dụng.

Nếu bạn sử dụng CreateInstance hay CreateInstanceFrom để tạo đối tượng kiểu MBV trong

một miền ứng dụng khác, đối tượng sẽ được tạo nhưng tham chiếu trả về sẽ không chỉ đến đối

tượng đó. Do cách thức đối tượng MBV vượt qua biên miền ứng dụng, tham chiếu này sẽ chỉ

đến một bản sao của đối tượng được tạo tự động trong miền ứng dụng cục bộ. Chỉ khi bạn tạo

một kiểu MBR thì tham chiếu trả về mới chỉ đến đối tượng trong miền ứng dụng khác (xem

mục 3.2 để biết thêm chi tiết về kiểu MBV và MBR).

Kỹ thuật chung để đơn giản hóa việc quản lý các miền ứng dụng là sử dụng lớp điều khiển

(controller class). Một lớp điều khiển là một kiểu MBR tùy biến. Bạn hãy tạo một miền ứng

dụng rồi tạo đối tượng lớp điều khiển trong miền ứng dụng này bằng phương thức

CreateInstance. Lớp điều khiển hiện thực các chức năng cần thiết cho ứng dụng để thao tác

miền ứng dụng và các nội dung của nó. Các chức năng này có thể bao gồm: nạp assembly, tạo

thêm miền ứng dụng, dọn dẹp trước khi xóa miền ứng dụng, hay liệt kê các phần tử chương

trình (bạn không thể thực hiện ở bên ngoài miền ứng dụng).

Ví dụ dưới đây trình bày cách sử dụng một lớp điều khiển có tên là PluginManager. Khi đã

được tạo trong một miền ứng dụng, PluginManager cho phép bạn tạo đối tượng của các lớp có

hiện thực giao diện IPlugin, chạy và dừng các plug-in đó, và trả về danh sách các plug-in

hiện được nạp.

using

using

using

using



System;

System.Reflection;

System.Collections;

System.Collections.Specialized;



// Giao diện chung cho tất cả các plug-in.

public interface IPlugin {



82

Chương 3: Miền ứng dụng, cơ chế phản chiếu, và siêu dữ liệu



}



void Start();

void Stop();



// Một hiện thực đơn giản cho giao diện Iplugin

// để minh họa lớp điều khiển PluginManager.

public class SimplePlugin : IPlugin {

public void Start() {

Console.WriteLine(AppDomain.CurrentDomain.FriendlyName +

": SimplePlugin starting...");

}

public void Stop() {



83

Chương 3: Miền ứng dụng, cơ chế phản chiếu, và siêu dữ liệu



}



Console.WriteLine(AppDomain.CurrentDomain.FriendlyName +

": SimplePlugin stopping...");



}

// Lớp điều khiển, quản lý việc nạp và thao tác

// các plug-in trong miền ứng dụng của nó.

public class PluginManager : MarshalByRefObject {

// ListDictionary giữ tham chiếu đến các plug-in.

private ListDictionary plugins = new ListDictionary();

// Phương thức khởi dựng mặc định.

public PluginManager() {}

// Phương thức khởi dựng nhận danh sách các plug-in.

public PluginManager(ListDictionary pluginList) {

// Nạp các plug-in đã được chỉ định.

foreach (string plugin in pluginList.Keys) {

}



this.LoadPlugin((string)pluginList[plugin], plugin);



}

// Nạp assembly và tạo plug-in được chỉ định.

public bool LoadPlugin(string assemblyName, string pluginName) {

try {

// Nạp assembly.

Assembly assembly = Assembly.Load(assemblyName);

// Tạo plug-in mới.

IPlugin plugin =

(IPlugin)assembly.CreateInstance(pluginName, true);

if (plugin != null) {

// Thêm plug-in mới vào ListDictionary.

plugins[pluginName] = plugin;

return true;



}



} else {

return false;

}

} catch {

return false;

}



public void StartPlugin(string plugin) {

// Lấy một plug-in từ ListDictionary và

// gọi phương thức Start.

((IPlugin)plugins[plugin]).Start();

}



84

Chương 3: Miền ứng dụng, cơ chế phản chiếu, và siêu dữ liệu

public void StopPlugin(string plugin) {

// Lấy một plug-in từ ListDictionary và

// gọi phương thức Stop.

((IPlugin)plugins[plugin]).Stop();

}

public ArrayList GetPluginList() {

// Trả về danh sách các plug-in.

return new ArrayList(plugins.Keys);

}



}



public class CreateInstanceExample {

public static void Main() {

// Tạo một miền ứng dụng mới.

AppDomain domain1 = AppDomain.CreateDomain("NewAppDomain1");

// Tạo một PluginManager trong miền ứng dụng mới

// bằng phương thức khởi dựng mặc định.

PluginManager manager1 =

(PluginManager)domain1.CreateInstanceAndUnwrap(

"CreateInstanceExample", "PluginManager");

// Nạp một plug-in mới vào NewAppDomain1.

manager1.LoadPlugin("CreateInstanceExample", "SimplePlugin");

// Chạy và dừng plug-in trong NewAppDomain1.

manager1.StartPlugin("SimplePlugin");

manager1.StopPlugin("SimplePlugin");

// Tạo một miền ứng dụng mới.

AppDomain domain2 = AppDomain.CreateDomain("NewAppDomain2");

// Tạo một ListDictionary chứa các plug-in.

ListDictionary pluginList = new ListDictionary();

pluginList["SimplePlugin"] = "CreateInstanceExample";

// Tạo một PluginManager trong miền ứng dụng mới

// và chỉ định danh sách các plug-in.

PluginManager manager2 =

(PluginManager)domain1.CreateInstanceAndUnwrap(

"CreateInstanceExample", "PluginManager", true, 0,

null, new object[] {pluginList}, null, null, null);

// Hiển thị các plug-in đã được nạp vào NewAppDomain2.

Console.WriteLine("Plugins in NewAppDomain2:");

foreach (string s in manager2.GetPluginList()) {

Console.WriteLine(" - " + s);

}



}

}



// Nhấn Enter để thoát.

Console.ReadLine();



85

Chương 3: Miền ứng dụng, cơ chế phản chiếu, và siêu dữ liệu



8



Truyền dữ liệu giữa các miền ứng dụng







Bạn cần một cơ chế đơn giản để truyền dữ liệu trạng thái hay cấu hình giữa các

miền ứng dụng.







Dùng các phương thức SetData và GetData của lớp AppDomain.



Dữ liệu có thể được truyền qua các miền ứng dụng như đối số hay trị trả về khi bạn cho gọi

các thành viên của các đối tượng hiện có trong các miền ứng dụng. Việc truyền dữ liệu qua

các miền ứng dụng được thực hiện dễ dàng giống như truyền dữ liệu trong cùng một miền

ứng dụng.

Mọi miền ứng dụng đều duy trì một vùng đệm dữ liệu (data cache) chứa một tập các cặp

“tên/giá trị”. Hầu hết nội dung của vùng đệm dữ liệu phản ánh các thiết lập cấu hình của miền

ứng dụng, như các giá trị từ đối tượng AppDomainSetup được cung cấp trong quá trình tạo

miền ứng dụng (xem mục 3.1). Vùng đệm dữ liệu này có thể được sử dụng để trao đổi dữ liệu

giữa các miền ứng dụng hay lưu trữ các giá trị tạm thời dùng trong cùng một miền ứng dụng.

Phương thức SetData thực hiện việc kết hợp một khóa dạng chuỗi với một đối tượng và lưu

trữ nó vào vùng đệm dữ liệu của miền ứng dụng. Phương thức GetData thực hiện công việc

ngược lại là lấy lại đối tượng từ vùng đệm dữ liệu thông qua khóa. Nếu mã lệnh trong một

miền ứng dụng gọi phương thức SetData hay GetData để truy xuất vùng đệm dữ liệu của miền

ứng dụng khác, thì đối tượng dữ liệu phải hỗ trợ ngữ nghĩa marshal-by-value hay marshal-byreference, nếu không thì ngoại lệ System.Runtime.Serialization.SerializationException

sẽ bị ném (xem mục 3.3 để biết thêm chi tiết về cách truyền đối tượng qua các miền ứng

dụng). Đoạn mã sau trình bày cách sử dụng phương thức SetData và GetData để truyền một

System.Collections.ArrayList giữa hai miền ứng dụng.

using System;

using System.Reflection;

using System.Collections;

public class ListModifier {

public ListModifier () {



}



// Nhận danh sách từ đệm dữ liệu.

ArrayList list =

(ArrayList)AppDomain.CurrentDomain.GetData("People");

// Thay đổi danh sách.

list.Add("Tam");



}

public class PassDataExample {

public static void Main() {

// Tạo một miền ứng dụng mới.

AppDomain domain = AppDomain.CreateDomain("Test");

// Tạo một ArrayList và thêm thông tin vào.

ArrayList list = new ArrayList();

list.Add("Phuong");

list.Add("Phong");

list.Add("Nam");



86

Chương 3: Miền ứng dụng, cơ chế phản chiếu, và siêu dữ liệu

// Đặt danh sách vào vùng đệm dữ liệu của miền ứng dụng mới.

domain.SetData("People", list);

// Tạo một ListModifier trong miền ứng dụng mới

// sẽ thay đổi nội dung của list trong vùng đệm dữ liệu.

domain.CreateInstance("03-08", "ListModifier");

// Nhận lại danh sách và hiển thị nội dung của nó.

foreach (string s in (ArrayList)domain.GetData("People")) {

Console.WriteLine(s);

}



}



// Nhấn Enter để thoát.

Console.ReadLine();



}



9







Giải phóng assembly và miền ứng dụng

Bạn cần giải phóng các assembly hay các miền ứng dụng lúc thực thi.

Không có cách nào để giải phóng các assembly riêng lẻ. Bạn có thể giải phóng toàn

bộ một miền ứng dụng bằng phương thức tĩnh AppDomain.Unload, đồng thời với

việc giải phóng miền ứng dụng là tất cả các assembly đã được nạp vào miền ứng

dụng đó cũng được giải phóng.



Cách duy nhất để giải phóng một assembly là giải phóng cả miền ứng dụng mà nó đã được

nạp vào. Đáng tiếc, việc giải phóng một miền ứng dụng cũng sẽ giải phóng luôn tất cả các

assembly đã được nạp vào đó. Đây là một giới hạn yêu cầu bạn phải tổ chức và quản lý tốt

cấu trúc miền ứng dụng và assembly.

Khi giải phóng một miền ứng dụng bằng phương thức tĩnh AppDomain.Unload, bạn cần truyền

cho nó một tham chiếu AppDomain đến miền ứng dụng cần giải phóng. Bạn không thể giải

phóng miền ứng dụng mặc định do CLR tạo lúc startup. Đoạn mã dưới đây trình bày cách sử

dụng phương thức Unload.

// Tạo một miền ứng dụng mới.

AppDomain newDomain = AppDomain.CreateDomain("New Domain");

// Nạp assembly vào miền ứng dụng mày.

§

// Giải phóng miền ứng dụng.

AppDomain.Unload(newDomain);



Phương thức Unload chặn các tiểu trình mới đi vào miền ứng dụng được chỉ định và gọi

phương thức Thread.Abort trên tất cả các tiểu trình hiện đang chạy trong miền ứng dụng này.

Nếu tiểu trình gọi phương thức Unload hiện đang chạy trong miền ứng dụng cần giải phóng

thì một tiểu trình khác sẽ được khởi chạy để thực hiện quá trình giải phóng. Nếu có vấn đề

trong việc giải phóng miền ứng dụng, ngoại lệ System.CannotUnloadAppDomainException sẽ

bị ném bởi tiểu trình thực hiện quá trình giải phóng.

Trong khi miền ứng dụng đang được giải phóng, CLR gọi thực thi các phương thức giải

phóng của tất cả các đối tượng trong miền ứng dụng. Tùy thuộc vào số lượng đối tượng và

bản chất của các phương thức giải phóng mà quá trình này có thể mất một khoảng thời gian

nào đó. Phương thức AppDomain.IsFinalizingForUnload trả về true nếu miền ứng dụng đang



Xem Thêm
Tải bản đầy đủ (.doc) (563 trang)

×