1. Trang chủ
  2. » Công Nghệ Thông Tin

Các giải pháp lập trình CSharp- P10 pdf

10 373 0
Tài liệu đã được kiểm tra trùng lặp

Đang tải... (xem toàn văn)

THÔNG TIN TÀI LIỆU

Thông tin cơ bản

Định dạng
Số trang 10
Dung lượng 2,63 MB

Các công cụ chuyển đổi và chỉnh sửa cho tài liệu này

Nội dung

Khi bạn truyền một đối tượng marshal-by-value MBV qua các miền ứng dụng, bộ thực thi sẽ tạo một thể hiện mới của đối tượng này trong miền ứng dụng đích.. Do đó, việc truyền các tham chi

Trang 1

§

}

3. Tránh n p các assembly không c n thi t vào mi n ng d ng Tránh n p các assembly không c n thi t vào mi n ng d ng ạ ạ ầ ầ ế ế ề ứ ề ứ ụ ụ

Bạn cần chuyển một tham chiếu đối tượng qua lại giữa các miền ứng dụng khác

nhau; tuy nhiên, bạn không muốn CLR nạp siêu dữ liệu mô tả kiểu của đối

tượng vào các miền ứng dụng trung gian.

Đóng gói tham chiếu đối tượng trong một System.Runtime.Remoting.ObjectHandle

và khi cần truy xuất đối tượng thì khôi phục lại.

Khi bạn truyền một đối tượng marshal-by-value (MBV) qua các miền ứng dụng, bộ thực thi sẽ

tạo một thể hiện mới của đối tượng này trong miền ứng dụng đích Điều này có nghĩa là bộ thực thi phải nạp assembly chứa siêu dữ liệu mô tả kiểu của đối tượng vào các miền ứng dụng

Do đó, việc truyền các tham chiếu MBV qua các miền ứng dụng trung gian sẽ dẫn đến việc bộ

thực thi nạp các assembly không cần thiết vào các miền ứng dụng này Một khi đã được nạp thì các assembly thừa này sẽ không được giải phóng khỏi miền ứng dụng nếu không giải phóng cả miền ứng dụng chứa chúng (xem mục 3.9)

Lớp ObjectHandle cho phép bạn đóng gói tham chiếu đối tượng để truyền qua các miền ứng dụng mà bộ thực thi không phải nạp thêm assembly Khi đối tượng này đến miền ứng dụng đích, bạn có thể khôi phục tham chiếu đối tượng, bộ thực thi sẽ nạp các assembly cần thiết và cho phép bạn truy xuất đến đối tượng như bình thường Để đóng gói một đối tượng (ví dụ

System.Data.DataSet), bạn có thể thực hiện như sau:

// Tạo một DataSet mới.

System.Data.DataSet data1 = new System.Data.DataSet();

// Cấu hình/thêm dữ liệu cho DataSet.

§

// Đóng gói DataSet.

System.Runtime.Remoting.ObjectHandle objHandle =

new System.Runtime.Remoting.ObjectHandle(data1);

Để khôi phục một đối tượng, sử dụng phương thức ObjectHandle.Unwrap và ép kiểu trả về cho phù hợp, ví dụ:

// Khôi phục DataSet từ ObjectHandle.

System.Data.DataSet data2 =

(System.Data.DataSet)objHandle.Unwrap();

Trang 2

4. T o ki u không th v T o ki u không th v ạ ể ạ ể ể ượ ể ượ t qua biên mi n ng d ng t qua biên mi n ng d ng ề ứ ề ứ ụ ụ

Bạn cần tạo một kiểu dữ liệu sao cho các thể hiện của kiểu này không thể được

truy xuất từ mã lệnh ở các miền ứng dụng khác.

Phải chắc chắn kiểu dữ liệu thuộc dạng nonremotable, tức là không thể tuần tự

hóa cũng như không dẫn xuất từ lớp MarshalByRefObject

Đôi khi bạn muốn kiểu dữ liệu nào đó chỉ được giới hạn truy xuất trong phạm vi của miền ứng

dụng Để tạo kiểu dữ liệu dạng nonremotable, phải chắc rằng kiểu này không phải là

khả-tuần-tự-hóa và cũng không dẫn xuất (trực tiếp hay gián tiếp) từ lớp MarshalByRefObject Những điều kiện này sẽ đảm bảo rằng trạng thái của đối tượng không thể được truy xuất từ các miền ứng dụng khác (các đối tượng này không thể được sử dụng làm đối số hay giá trị trả

về trong các lời gọi phương thức liên miền ứng dụng)

Điều kiện kiểu dữ liệu không phải là khả-tuần-tự-hóa được thực hiện dễ dàng do một lớp không thừa kế khả năng tuần tự hóa từ lớp cha của nó Để bảo đảm một kiểu không phải là khả-tuần-tự-hóa, bạn phải chắc chắn rằng đặc tính System.SerializableAttribute không được áp dụng khi khai báo kiểu

Bạn cần lưu ý khi đảm bảo một lớp không được truyền bằng tham chiếu Nhiều lớp trong thư

viện lớp NET dẫn xuất trực tiếp hay gián tiếp từ MarshalByRefObject; bạn phải cẩn thận không dẫn xuất lớp của bạn từ các lớp này Những lớp cơ sở thông dụng dẫn xuất từ

MarshalByRefObject bao gồm: System.ComponentModel.Component, System.IO.Stream,

System.IO.TextReader, System.IO.TextWriter, System.NET.WebRequest, và System.Net WebResponse (xem tài liệu NET Framework SDK để có danh sách đây đu các lớp dẫn xuất từ

MarshalByRefObject)

5. N p assembly vào mi n ng d ng hi n hành N p assembly vào mi n ng d ng hi n hành ạ ạ ề ứ ề ứ ụ ụ ệ ệ

Bạn cần nạp một assembly vào miền ứng dụng lúc thực thi.

Sử dụng phương thức tĩnh Load hay LoadFrom của lớp

System.Reflection.Assembly

Bộ thực thi tự động nạp các assembly mà assembly của bạn tham chiếu đến lúc biên dịch Tuy nhiên, bạn cũng có thể chỉ thị cho bộ thực thi nạp assembly Các phương thức Load và

LoadFrom đều thực hiện một công việc là nạp một assembly vào miền ứng dụng hiện hành, và

cả hai đều trả về một đối tượng Assembly mô tả assembly vừa được nạp Sự khác biệt giữa hai phương thức là danh sách các đối số được cung cấp để nhận dạng assembly cần nạp, và cách thức bộ thực thi định vị assembly này

Phương thức Load cung cấp nhiều dạng thức cho phép chỉ định assembly cần nạp, bạn có thể

sử dụng một trong những dạng sau:

• Một string chứa tên đầy đủ hay tên riêng phân đê nhận dạng assembly

Trang 3

• Một mảng byte chứa dữ liệu câu thành assembly

Thông thường, tên của assembly được sử dụng để nạp assembly Tên đầy đủ của một assembly bao gồm: tên, phiên bản, ban đia, và token khóa công khai, được phân cách bởi dấu phẩy (ví dụ: System.Data, Version=1.0.5000.0, Culture=neutral, PublicKeyToken= b77a5c561934e089) Để chỉ định một assembly không có tên mạnh, sử dụng

PublicKeyToken=null Bạn cũng có thể sử dụng tên ngắn để nhận dạng một assembly nhưng ít nhất phải cung cấp tên của assembly (không có phần mở rộng) Đoạn mã dưới đây trình bày các cách sử dụng phương thức Load:

// Nạp assembly System.Data dùng tên đầy đủ.

string name1 = "System.Data,Version=1.0.5000.0," +

"Culture=neutral,PublicKeyToken=b77a5c561934e089";

Assembly a1 = Assembly.Load(name1);

// Nạp assembly System.Xml dùng AssemblyName.

AssemblyName name2 = new AssemblyName();

name2.Name = "System.Xml";

name2.Version = new Version(1,0,5000,0);

name2.CultureInfo = new CultureInfo("");

name2.SetPublicKeyToken(

new byte[] {0xb7,0x7a,0x5c,0x56,0x19,0x34,0xe0,0x89});

Assembly a2 = Assembly.Load(name2);

// Nạp assembly SomeAssembly dùng tên ngắn.

Assembly a3 = Assembly.Load("SomeAssembly");

Khi phương thức Load được gọi, bộ thực thi thực hiện quá trình định vị và nạp assembly Dưới

đây sẽ tóm tắt quá trình này; bạn tham khảo tài liệu NET Framework SDK để biết thêm chi

tiết

1 Nếu bạn chỉ định assembly tên mạnh, phương thức Load sẽ áp dụng version policy (chính sách phiên bản) và publisher policy (chính sách nhà phát hành) để cho phep kha năng “chuyên tiếp” (redirect) đến môt phiên ban assembly khác Version policy được

chỉ định trong file cấu hình máy tính hay ứng dụng của bạn bằng phần tử

<bindingRedirect> Publisher policy được chỉ định trong các assembly đăc biêt được cài đặt bên trong GAC (Global Assembly Cache).

2 Một khi đã xác định đúng phiên bản của assembly cần sử dụng, bộ thực thi sẽ cố gắng

nạp các assembly tên mạnh từ GAC.

3 Nếu assembly không có tên mạnh hoặc không được tìm thấy trong GAC, bộ thực thi sẽ

tìm phần tử <codeBase> trong các file cấu hình máy tính và ứng dụng Phần tử

<codeBase> ánh xạ tên của assembly thành một file hay một URL Nếu assembly có tên

mạnh, <codeBase> có thể chỉ đến bất kỳ vị trí nào kể cả các URL dựa-trên-Internet; nếu

Trang 4

không, <codeBase> phải chỉ đến một thư mục co vi tri tương đối so với thư mục ứng dụng Nếu assembly không tồn tại trong vị trí được chỉ định, phương thức Load sẽ ném ngoại lệ System.IO.FileNotFoundException

4 Nếu không có phần tử <codeBase> tương ứng với assembly, bộ thực thi sẽ tìm assembly

bằng kỹ thuật probing Quá trình probing sẽ tìm file đầu tiên có tên của assembly (với phần mở rộng là dll hay exe) trong các vị trí:

• Thư mục gốc của ứng dụng

• Các thư mục con cua thư mục gốc phù hợp với tên và ban đia của assembly

• Các thư mục con (cua thư mục gôc) do ngươi dung chi đinh

Phương thức Load là cách dễ nhất để tìm và nạp các assembly, nhưng cũng có thể tốn nhiều chi phí cho việc dò trong nhiều thư mục để tìm các assembly có tên yếu Phương thức

LoadFrom cho phép bạn nạp assembly từ một vị trí xác định, nếu không tìm thấy nó sẽ ném ngoại lệ FileNotFoundException Bộ thực thi sẽ không cố tìm assembly như phương thức Load

—phương thức LoadFrom không hỗ trợ GAC, policy, phần tử <codeBase> hay probing Dưới

đây là đoạn mã trình bày cách sử dụng LoadFrom để nạp c:\shared\MySharedAssembly.dll Lưu

ý rằng, khác với Load, LoadFrom yêu cầu bạn chỉ định phần mở rộng của file assembly

// Nạp assembly có tên là c:\shared\MySharedAssembly.dll

Assembly a4 = Assembly.LoadFrom(@"c:\shared\MySharedAssembly.dll");

6. Th c thi assembly mi n ng d ng khác Th c thi assembly mi n ng d ng khác ự ự ở ề ứ ở ề ứ ụ ụ

Bạn cần thực thi một assembly ở một miền ứng dụng khác vơi miền ứng dụng

hiện hành.

Gọi phương thức ExecuteAssembly của đối tượng AppDomain đai diên cho miền

ứng dụng, và chỉ định tên của assembly cần thực thi.

Nếu bạn có một assembly khả-thực-thi và muốn nạp để thực thi nó trong một miền ứng dụng, phương thức ExecuteAssembly sẽ giúp bạn Phương thức ExecuteAssembly có bốn dạng thức khác nhau Dạng thức đơn giản nhất chỉ nhận vào một kiểu string chứa tên của assembly cần

thực thi; bạn có thể chỉ định một file cục bộ hay một URL Một dạng thức khác cho phép bạn chỉ định chứng cứ (evidence) cho assembly (xem mục 13.10) và các đối số để truyền đến điểm

nhập của assembly (tương đương với các đối số dòng lệnh)

Phương thức ExecuteAssembly nạp assembly được chỉ định và thực thi phương thức được định nghĩa trong siêu dữ liệu là điểm nhập của assembly (thường là phương thức Main) Nếu assembly được chỉ định không có khả năng thực thi, ExecuteAssembly sẽ ném ngoại lệ

System.Runtime.InteropServices.COMException Bộ thực thi không thực thi assembly trong một tiểu trình mới, vì thế quyền kiểm soát sẽ không trả về cho đến khi quá trình thực thi của assembly kết thúc Do ExecuteAssembly nạp một assembly bằng tên riêng phân (chỉ có tên

file), CLR sẽ không dùng GAC hay probing để tìm assembly (xem mục 3.5 để biết thêm chi

tiết)

Trang 5

assembly Lớp ExecuteAssemblyExample tạo một AppDomain và thực thi chính nó trong

AppDomain bằng phương thức ExecuteAssembly Kết quả là có hai bản sao của

ExecuteAssemblyExample được nạp vào hai miền ứng dụng khác nhau

using System;

public class ExecuteAssemblyExample {

public static void Main(string[] args) {

// Nếu assembly đang thực thi trong một AppDomain

// có tên thân thiện là "NewAppDomain"

// thì không tạo AppDomain mới Điều này sẽ

// tránh một vòng lặp vô tận tạo AppDomain.

if (AppDomain.CurrentDomain.FriendlyName != "NewAppDomain") {

// Tạo miền ứng dụng mới có tên là "NewAppDomain".

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

// Thực thi assembly này trong AppDomain mới và

// truyền mảng các đối số dòng lệnh.

domain.ExecuteAssembly("ExecuteAssemblyExample.exe",

null, args);

}

// Hiển thị các đối số dòng lệnh lên màn hình

// cùng với tên thân thiện của AppDomain.

foreach (string s in args) {

Console.WriteLine(AppDomain.CurrentDomain.FriendlyName +

" : " + s);

}

}

}

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

Bạn cần thể hiện hóa một kiểu trong một miền ứng dụng khác vơi miền ứng

dụng hiện hành.

Trang 6

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

AppDomain đai 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 có tên là

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 System;

using System.Reflection;

Trang 7

using System.Collections.Specialized;

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

public interface IPlugin {

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() {

Trang 8

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 =

Trang 9

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();

}

Trang 10

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");

Ngày đăng: 08/07/2014, 17:20

TỪ KHÓA LIÊN QUAN