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

Các giải pháp lập trình C Sharp_2

53 14 0

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

Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống

THÔNG TIN TÀI LIỆU

Thông tin cơ bản

Định dạng
Số trang 53
Dung lượng 738,66 KB

Nội dung

Trong chương trình viết bằng ngôn ngữ C#, để miêu tả các chuỗi văn bản, ta thường dùng biến thuộc kiểu string hay String. string hay String là các class đối tượng có sẵn trong môi trường .Net được dùng để quản lý chuỗi văn bản. Để chuyển chuỗi sang 1 mảng ký tự, bạn có thể gọi tác vụ ToCharArray() của biến string hay String. Thí dụ sau là đoạn code C# demo việc chuyển chuỗi sang mảng các ký tự...

53 Chương 2: Thao tác liệu H ầu hết ứng dụng cần thao tác loại liệu Microsoft NET Framework cung cấp nhiều kỹ thuật để đơn giản hóa hay nâng cao hiệu thao tác liệu thông dụng Chương đề cập kỹ thuật sau: Thao tác chuỗi cách hiệu (mục 2.1) Mô tả kiểu liệu sở kiểu mã hóa khác (mục 2.2, 2.3, 2.4) Sử dụng biểu thức quy để xác nhận tính hợp lệ thao tác chuỗi (mục 2.5 2.6) Làm việc với ngày (mục 2.7 2.8) Làm việc với mảng tập hợp (mục 2.9, 2.10, 2.11) Tuần tự hóa trạng thái đối tượng lưu vào file (mục 2.12) 2.1 Thao tác chuỗi cách hiệu Bạn cần thao tác nội dung đối tượng String tránh chi phí việc tự động tạo đối tượng String tính khơng đổi đối tượng String Sử dụng lớp System.Text.StringBuilder để thực thao tác, sau chuyển kết thành String phương thức StringBuilder.ToString Các đối tượng String NET không đổi, nghĩa tạo chúng khơng thể bị thay đổi Ví dụ, bạn tạo String cách nối số ký tự chuỗi, thêm phần tử vào cuối String có, thực thi tạo String chứa kết (chứ String cũ bị thay đổi) Do nảy sinh chi phí đáng kể ứng dụng bạn thường xuyên thao tác String Lớp StringBuilder khắc phục vấn đề cách cung cấp đệm ký tự, cho phép thao tác nội dung mà thực thi khơng phải tạo đối tượng để chứa kết sau lần thay đổi Bạn tạo đối tượng StringBuilder rỗng khởi tạo nội dung String có Sau đó, thao tác nội dung StringBuilder phương thức nạp chồng (cho phép bạn chèn, thêm dạng chuỗi kiểu liệu khác nhau) Cuối cùng, gọi StringBuilder.ToString để chuyển nội dung StringBuilder thành String Khi bạn thêm liệu vào chuỗi, có hai thuộc tính quan trọng ảnh hưởng đến hoạt động StringBuilder Capacity Length Capacity mơ tả kích thước đệm StringBuilder, cịn Length mơ tả kích thước chuỗi ký tự đệm Nếu việc thêm liệu vào StringBuilder làm kích thước chuỗi (Length) vượt kích thước đệm (Capacity) StringBuilder cấp phát đệm để chứa chuỗi Nếu thiếu cẩn thận, việc cấp phát đệm phủ định lợi ích việc sử dụng StringBuilder Do đó, biết xác kích thước chuỗi, biết kích thước tối đa chuỗi, bạn tránh việc cấp phát đệm mức cần thiết cách thiết lập thuộc tính Capacity định kích thước đệm lúc tạo StringBuilder Khi thiết lập thuộc tính Capacity Length, cần ý điểm sau: 54 Chương 2: Thao tác liệu • Nếu bạn thiết lập giá trị Capacity nhỏ giá trị Length, thuộc tính Capacity ném ngoại lệ System.ArgumentOutOfRangeException • Nếu bạn thiết lập giá trị Length nhỏ kích thước chuỗi có đệm, chuỗi bị cắt bớt phần lớn • Nếu bạn thiết lập giá trị Length lớn kích thước chuỗi, đệm "lấp" thêm khoảng trắng cho với Length Việc thiết lập giá trị Length lớn giá trị Capacity tự động điều chỉnh Capacity cho với Length Phương thức ReverseString minh họa cách sử dụng lớp StringBuilder để đảo chuỗi Nếu không sử dụng lớp StringBuilder để thực thao tác tốn chi phí đáng kể, đặc biệt chuỗi nguồn dài Việc khởi tạo StringBuilder với kích thước chuỗi nguồn bảo đảm không cần phải cấp phát lại đệm trình đảo chuỗi public static string ReverseString(string str) { // Kiểm tra trường hợp không cần đảo chuỗi if (str == null || str.Length == 1) { return str; } // Tạo StringBuilder với sức chứa cần thiết System.Text.StringBuilder revStr = new System.Text.StringBuilder(str.Length); // Duyệt ngược chuỗi nguồn ký tự // thêm ký tự đọc vào StringBuilder for (int count = str.Length-1; count > -1; count ) { revStr.Append(str[count]); } // Trả chuỗi đảo return revStr.ToString(); } 2.2 Mã hóa chuỗi kiểu mã hóa ký tự Bạn cần trao đổi liệu dạng ký tự với hệ thống sử dụng kiểu mã hóa khác với UTF-16 (kiểu mã hóa sử dụng CRL) Sử dụng lớp System.Text.Encoding lớp để chuyển đổi ký tự kiểu mã hóa khác Unicode khơng phải kiểu mã hóa nhất, UTF-16 khơng phải cách biểu diễn ký tự Unicode Khi ứng dụng cần trao đổi liệu ký tự với hệ thống bên (đặc biệt hệ thống cũ), liệu cần phải chuyển đổi UTF-16 kiểu mã hóa mà hệ thống hỗ trợ Lớp trừu tượng Encoding, lớp cung cấp chức để chuyển ký tự qua lại nhiều kiểu mã hóa khác Mỗi thể lớp hỗ trợ việc chuyển đổi UTF-16 kiểu mã hóa khác Phương thức tĩnh Encoding.GetEncoding nhận vào tên số hiệu trang mã (code page number) kiểu mã hóa trả thể lớp mã hóa tương ứng 55 Chương 2: Thao tác liệu Bảng 2.1 liệt kê vài kiểu mã ký tự số hiệu trang mã mà bạn phải truyền cho phương thức GetEncoding để tạo thể lớp mã hóa tương ứng Bảng cung cấp thuộc tính tĩnh lớp Encoding đại diện cho phương thức GetEncoding tương ứng Bảng 2.1 Các lớp mã hóa ký tự Kiểu mã hóa Lớp ASCII ASCIIEncoding Mặc định (kiểu mã hóa hành hệ thống) Encoding UTF-7 UTF7Encoding Sử dụng GetEncoding(20127) hay thuộc tính ASCII GetEncoding(0) hay thuộc tính Default GetEncoding(65000) hay thuộc tính UTF7 GetEncoding(65001) hay thuộc tính UTF8 UTF-8 UTF8Encoding UTF-16 (Big Endian) UnicodeEncoding hay thuộc tính BigEndianUnicode UTF-16 (Little Endian) UnicodeEncoding hay thuộc tính Unicode Windows OS Encoding GetEncoding(1252) GetEncoding(1201) GetEncoding(1200) Sau lấy đối tượng lớp Encoding hỗ trợ kiểu mã hóa thích hợp, sử dụng phương thức GetBytes để chuyển chuỗi nguồn (được mã hóa theo UTF-16) thành mảng kiểu byte chứa ký tự mã hóa theo kiểu cần chuyển, sử dụng GetString để chuyển mảng byte thành chuỗi đích Ví dụ trình bày cách sử dụng vài lớp mã hóa: using System; using System.IO; using System.Text; public class CharacterEncodingExample { public static void Main() { // Tạo file giữ kết using (StreamWriter output = new StreamWriter("output.txt")) { // Tạo ghi file chuỗi chứa ký hiệu số PI string srcString = "Area = \u03A0r^2"; output.WriteLine("Source Text : " + srcString); // Ghi byte mã hóa theo UTF-16 // chuỗi nguồn file byte[] utf16String = Encoding.Unicode.GetBytes(srcString); output.WriteLine("UTF-16 Bytes: {0}", BitConverter.ToString(utf16String)); // Chuyển chuỗi nguồn mã hóa theo UTF-16 // thành UTF-8 ASCII byte[] utf8String = Encoding.UTF8.GetBytes(srcString); byte[] asciiString = Encoding.ASCII.GetBytes(srcString); // Ghi mảng byte mã hóa theo UTF-8 ASCII file 56 Chương 2: Thao tác liệu output.WriteLine("UTF-8 Bytes: {0}", BitConverter.ToString(utf8String)); output.WriteLine("ASCII Bytes: {0}", BitConverter.ToString(asciiString)); // Chuyển byte mã hóa theo UTF-8 ASCII // thành chuỗi mã hóa theo UTF-16 ghi file output.WriteLine("UTF-8 Text : {0}", Encoding.UTF8.GetString(utf8String)); output.WriteLine("ASCII Text : {0}", Encoding.ASCII.GetString(asciiString)); // Ghi liệu xuống file đóng file output.Flush(); output.Close(); } } } Chạy CharacterEncodingExample tạo file output.txt Mở file trình soạn thảo có hỗ trợ Unicode, bạn thấy kết sau: Source UTF-16 UTF-8 ASCII UTF-8 ASCII Text : Bytes: Bytes: Bytes: Text : Text : Area = Πr^2 41-00-72-00-65-00-61-00-20-00-3D-00-20-00-A0-03-72-00-5E-00-32-00 41-72-65-61-20-3D-20-CE-A0-72-5E-32 41-72-65-61-20-3D-20-3F-72-5E-32 Area = Πr^2 Area = ?r^2 Chú ý rằng, sử dụng UTF-16 ký tự mã hóa byte, hầu hết ký tự ký tự chuẩn nên byte cao (nếu sử dụng little-endian byte thấp viết trước) Do đó, hầu hết ký tự mã hóa số giống ba kiểu mã hóa, ngoại trừ ký hiệu PI mã hóa khác (được in đậm kết trên) Để mã hóa PI cần byte, đòi hỏi UTF-8 hỗ trợ nên thể Π, ASCII sử dụng byte nên thay PI mã 3F, mã dấu hỏi (?) Nếu chuyển ký tự Unicode sang ASCII kiểu mã hóa khác liệu Bất kỳ ký tự Unicode có mã ký tự khơng biểu diễn kiểu mã hóa đích bị bỏ qua chuyển đổi Lớp Encoding cung cấp phương thức tĩnh Covert để đơn giản hóa việc chuyển mảng byte từ kiểu mã hóa sang kiểu mã hóa khác khơng phải qua trung gian UTF-16 Ví dụ, dịng mã sau chuyển trực tiếp byte mảng asciiString từ ASCII sang UTF-8: byte[] utf8String = Encoding.Convert(Encoding.ASCII, Encoding.UTF8, asciiString); 2.3 Chuyển kiểu giá trị thành mảng kiểu byte Bạn cần chuyển kiểu giá trị thành mảng kiểu byte 57 Chương 2: Thao tác liệu Lớp System.BitConverter cung cấp phương thức tĩnh tiện lợi cho việc chuyển đổi qua lại mảng kiểu byte hầu hết kiểu giá trị bản—trừ kiểu decimal Để chuyển giá trị kiểu decimal sang mảng kiểu byte, bạn cần sử dụng đối tượng System.IO.BinaryWriter để ghi giá trị vào thể System.IO.MemoryStream, sau gọi phương thức Memorystream.ToArray Để có giá trị decimal từ mảng kiểu byte, bạn cần tạo đối tượng MemoryStream từ mảng kiểu byte, sau sử dụng thể System.IO.BinaryReader để đọc giá trị từ MemoryStream Phương thức tĩnh GetBytes lớp BitConverter cung cấp nhiều phiên nạp chồng cho phép chuyển hầu hết kiểu giá trị sang mảng kiểu byte Các kiểu hỗ trợ bool, char, double, short, int, long, float, ushort, uint, ulong Lớp BitConverter cung cấp phương thức tĩnh cho phép chuyển mảng kiểu byte thành kiểu giá trị chuẩn ToBoolean, ToUInt32, ToDouble, Ví dụ sau minh họa cách chuyển giá trị bool int thành mảng kiểu byte, ngược lại Đối số thứ hai ToBoolean ToUInt32 cho biết vị trí (tính từ 0) mảng byte mà BitConverter lấy byte kể từ để tạo giá trị liệu byte[] b = null; // Chuyển giá trị bool thành mảng kiểu byte hiển thị b = BitConverter.GetBytes(true); Console.WriteLine(BitConverter.ToString(b)); // Chuyển mảng kiểu byte thành giá trị bool hiển thị Console.WriteLine(BitConverter.ToBoolean(b,0)); // Chuyển giá trị int thành mảng kiểu byte hiển thị b = BitConverter.GetBytes(3678); Console.WriteLine(BitConverter.ToString(b)); // Chuyển mảng kiểu byte thành giá trị int hiển thị Console.WriteLine(BitConverter.ToInt32(b,0)); Đối với kiểu decimal, lớp BitConverter không hỗ trợ, nên bạn phải sử dụng thêm MemoryStream BinaryWriter // Tạo mảng kiểu byte từ giá trị decimal public static byte[] DecimalToByteArray (decimal src) { // Tạo MemoryStream làm đệm chứa liệu nhị phân using (MemoryStream stream = new MemoryStream()) { // Tạo BinaryWriter để ghi liệu nhị phân vào stream using (BinaryWriter writer = new BinaryWriter(stream)) { // Ghi giá trị decimal vào BinaryWriter/MemoryStream writer.Write(src); // Trả mảng kiểu byte return stream.ToArray(); } } } 58 Chương 2: Thao tác liệu Để chuyển mảng kiểu byte thành giá trị decimal, sử dụng BinaryReader để đọc từ MemoryStream // Tạo giá trị decimal từ mảng kiểu byte public static decimal ByteArrayToDecimal (byte[] src) { // Tạo MemoryStream chứa mảng using (MemoryStream stream = new MemoryStream(src)) { // Tạo BinaryReader để đọc từ stream using (BinaryReader reader = new BinaryReader(stream)) { // Đọc trả giá trị decimal từ // BinaryReader/MemoryStream return reader.ReadDecimal(); } } } Lớp BitConverter cung cấp phương thức ToString để tạo String chứa giá trị mảng Gọi ToString truyền đối số mảng byte trả String chứa giá trị thập lục phân byte mảng, giá trị cách dấu gạch nối, ví dụ “34-A7-2C” Tuy nhiên, khơng có phương thức tạo mảng kiểu byte từ chuỗi theo định dạng 2.4 Mã hóa liệu nhị phân thành văn Bạn cần chuyển liệu nhị phân sang dạng cho lưu trữ file văn ASCII (chẳng hạn file XML), gởi e-mail Sử dụng phương thức tĩnh ToBase64String FromBase64String lớp System.Converter để chuyển đổi qua lại liệu nhị phân chuỗi mã hóa theo Base64 Base64 kiểu mã hóa cho phép bạn mơ tả liệu nhị phân dãy ký tự ASCII để chèn vào file văn e-mail, mà liệu nhị phân không cho phép Base64 làm việc nguyên tắc sử dụng byte để chứa byte liệu nguồn đảm bảo byte sử dụng bit thấp để chứa liệu Điều có nghĩa byte liệu mã hóa theo Base64 có dạng giống ký tự ASCII, nên lưu trữ truyền nơi đâu cho phép ký tự ASCII Lớp Convert cung cấp hai phương thức ToBase64String FromBase64String để mã hóa giải mã Base64 Tuy nhiên, trước mã hóa Base64, bạn phải chuyển liệu thành mảng kiểu byte; sau giải mã, bạn phải chuyển mảng kiểu byte trở kiểu liệu thích hợp (xem lại mục 2.2 2.3) Ví dụ sau minh họa cách sử dụng lớp Convert để mã hóa giải mã Base64 với chuỗi Unicode, giá trị int, giá trị decimal Đối với giá trị decimal, bạn phải sử dụng lại phương thức ByteArrayToDecimal DecimalToByteArray mục 2.3 // Mã hóa Base64 với chuỗi Unicode public static string StringToBase64 (string src) { 59 Chương 2: Thao tác liệu // Chuyển chuỗi thành mảng kiểu byte byte[] b = Encoding.Unicode.GetBytes(src); // Trả chuỗi mã hóa theo Base64 return Convert.ToBase64String(b); } // Giải mã chuỗi Unicode mã hóa theo Base64 public static string Base64ToString (string src) { // Giải mã vào mảng kiểu byte byte[] b = Convert.FromBase64String(src); // Trả chuỗi Unicode return Encoding.Unicode.GetString(b); } // Mã hóa Base64 với giá trị decimal public static string DecimalToBase64 (decimal src) { // Chuyển giá trị decimal thành mảng kiểu byte byte[] b = DecimalToByteArray(src); // Trả giá trị decimal mã hóa theo Base64 return Convert.ToBase64String(b); } // Giải mã giá trị decimal mã hóa theo Base64 public static decimal Base64ToDecimal (string src) { // Giải mã vào mảng kiểu byte byte[] b = Convert.FromBase64String(src); // Trả giá trị decimal return ByteArrayToDecimal(b); } // Mã hóa Base64 với giá trị int public static string IntToBase64 (int src) { // Chuyển giá trị int thành mảng kiểu byte byte[] b = BitConverter.GetBytes(src); // Trả giá trị int mã hóa theo Base64 return Convert.ToBase64String(b); } // Giải mã giá trị int mã hóa theo Base64 public static int Base64ToInt (string src) { // Giải mã vào mảng kiểu byte byte[] b = Convert.FromBase64String(src); // Trả giá trị int return BitConverter.ToInt32(b,0); } 60 Chương 2: Thao tác liệu Sử dụng biểu thức quy để kiểm tra liệu 2.5 nhập Bạn cần kiểm tra liệu nhập vào có với cấu trúc nội dung quy định trước hay khơng Ví dụ, bạn muốn bảo đảm người dùng nhập địa IP, số điện thoại, hay địa e-mail hợp lệ Sử dụng biểu thức quy để bảo đảm liệu nhập cấu trúc chứa ký tự quy định trước dạng thông tin Khi ứng dụng nhận liệu từ người dùng đọc liệu từ file, bạn nên giả định liệu chưa xác cần kiểm tra lại Một nhu cầu kiểm tra phổ biến xác định số điện thoại, số thẻ tín dụng, địa e-mail có dạng hay không Việc kiểm tra cấu trúc nội dung liệu không đảm bảo liệu xác giúp loại bỏ nhiều liệu sai đơn giản hóa việc kiểm tra sau Biểu thức quy (regular expression) cung cấp chế tốt để kiểm tra chuỗi có với cấu trúc quy định trước hay khơng, bạn lợi dụng tính cho mục đích kiểm tra liệu nhập Trước tiên, bạn phải xác định cú pháp biểu thức quy cho phù hợp với cấu trúc nội dung liệu cần kiểm tra, phần khó sử dụng biểu thức quy Biểu thức quy xây dựng hai yếu tố: trực kiện (literal) siêu ký tự (metacharacter) Trực kiện mô tả ký tự xuất mẫu mà bạn muốn so trùng; siêu ký tự hỗ trợ việc so trùng ký tự đại diện (wildcard), tầm trị, nhóm, lặp, điều kiện, chế điều khiển khác Ở không thảo luận đầy đủ cú pháp biểu thức quy (tham khảo tài liệu NET SDK để hiểu thêm biểu thức quy), bảng 2.2 mô tả siêu ký tự thường dùng Bảng 2.2 Các siêu ký tự thường dùng Siêu ký tự Mô tả Mọi ký tự trừ ký tự xuống dòng (\n) \d Ký tự chữ số thập phân (digit) \D Ký tự chữ số (non-digit) \s Ký tự whitespace (như khoảng trắng, tab ) \S Ký tự non-whitespace \w Ký tự word (gồm mẫu tự, chữ số, dấu gạch dưới) \W Ký tự non-word ^ Bắt đầu chuỗi dòng \A Bắt đầu chuỗi $ Kết thúc chuỗi dòng \z Kết thúc chuỗi 61 Chương 2: Thao tác liệu | Ngăn cách biểu thức so trùng, ví dụ AAA|ABA|ABB so trùng với AAA, ABA, ABB (các biểu thức so trùng từ trái sang) [abc] So trùng với ký tự nhóm, ví dụ [AbC] so trùng với A, b, C [^abc] So trùng với ký tự khơng thuộc ký tự nhóm, ví dụ [^AbC] không so trùng với A, b, or C so trùng với B, F,… [a-z] So trùng với ký tự thuộc khoảng này, ví dụ [A-C] so trùng với A, B, C ( ) Xác định biểu thức cho xem yếu tố đơn lẻ yếu tố trình bày bảng ? Xác định có khơng có ký tự biểu thức đứng trước nó, ví dụ A?B so trùng với B, AB, không so trùng với AAB * Xác định khơng có có nhiều ký tự biểu thức đứng trước nó, ví dụ A*B so trùng với B, AB, AAB, AAAB,… + Xác định có có nhiều ký tự biểu thức đứng trước nó, ví dụ A+B so trùng với AB, AAB, AAAB,… không so trùng với B {n} Xác định có n ký tự biểu thức đứng trước nó, ví dụ A{2} so trùng với AA {n,} Xác định có n ký tự biểu thức đứng trước nó, ví dụ A{2,} so trùng với AA, AAA, AAAA,… không so trùng với A {n, m} Xác định có từ n đến m ký tự đứng trước nó, ví dụ A{2,4} so trùng với AA, AAA, AAAA không so trùng với A AAAAA Khi liệu cần kiểm tra phức tạp cú pháp biểu thức quy phức tạp Ví dụ, dễ dàng kiểm tra liệu nhập chứa số hay có chiều dài tối thiểu, kiểm tra URL phức tạp Bảng 2.3 liệt kê số biểu thức quy dùng để kiểm tra kiểu liệu thơng dụng Bảng 2.3 Một số biểu thức quy thông dụng Kiểu liệu nhập Mô tả Biểu thức quy Số Chỉ chứa chữ số thập phân; ví dụ 5, 5683874674 ^\d+$ PIN Chứa chữ số thập phân, ví dụ 1234 ^\d{4}$ Mật đơn giản Chứa từ đến ký tự; ví dụ ghtd6f b8c7hogh ^\w{6,8}$ 62 Chương 2: Thao tác liệu Số thẻ tín dụng Chứa liệu phù hợp với cấu trúc hầu hết loại số thẻ tín dụng, ví dụ 4921835221552042 49218352-2155-2042 ^\d{4}-?\d{4}-?\d{4}?\d{4}$ [\w-]+ nghĩa chứa Địa e-mail nhiều ký tự word dấu gạch ngang, ví dụ ^[\w-]+@([\w]+\.)+[\w-]+$ some-body@adatum.com HTTP HTTPS URL Dữ liệu URL dựa-trên-HTTP hay dựa-trên-HTTPS, ví dụ http://www.microsoft.com ^https?://([\w]+\.)+[\w-]+(/[\w- / ?%=]*)?$ Một biết cú pháp biểu thức quy, bạn tạo đối tượng System.Text.RegularExpression.Regex cách truyền cho phương thức khởi dựng chuỗi chứa biểu thức quy Sau đó, gọi phương thức IsMatch đối tượng Regex truyền chuỗi cần kiểm tra, phương thức trả giá trị luận lý cho biết chuỗi có hợp lệ khơng Cú pháp biểu thức quy định Regex so trùng toàn chuỗi hay so trùng phần chuỗi (xem ^, \A, $, \z bảng 2.2) Phương thức ValidateInput minh họa cách kiểm tra chuỗi nhập biểu thức quy: public static bool ValidateInput(string regex, string input) { // Tạo đối tượng Regex dựa biểu thức quy Regex r = new Regex(regex); // Kiểm tra liệu nhập có trùng với biểu thức quy hay khơng return r.IsMatch(input); } Bạn sử dụng đối tượng Regex để kiểm tra nhiều chuỗi, khơng thể thay đổi biểu thức quy gắn cho nó; bạn phải tạo đối tượng Regex tương ứng với cấu trúc Phương thức ValidateInput tạo đối tượng Regex lần gọi, thay vào bạn sử dụng phương thức tĩnh nạp chồng IsMatch public static bool ValidateInput(string regex, string input) { // Kiểm tra liệu nhập có trùng với biểu thức quy hay khơng return Regex.IsMatch(input, regex); } 2.6 Sử dụng biểu thức quy biên dịch Bạn cần giảm thiểu tác động lên hiệu ứng dụng biểu thức quy phức tạp sử dụng thường xuyên Khi khởi tạo đối tượng System.Text.RegularExpressions.Regex, truyền thêm tùy chọn Compiled thuộc kiểu liệt kê System.Text.RegularExpressions 91 Chương 3: Miền ứng dụng, chế phản chiếu, siêu liệu // Kiểm tra xem someObject có phải StringReader hay không // cách thu lấy so sánh tham chiếu Type (sử dụng toán tử typeof) if (typeof(System.IO.StringReader) == someObject.GetType()) { // Làm § } C# cung cấp toán tử is để thực nhanh việc kiểm tra Ngoài ra, is trả true đối tượng cần kiểm tra dẫn xuất từ lớp định Đoạn mã kiểm tra xem someObject thể System.IO.TextReader, hay lớp dẫn xuất từ TextReader (như StringReader): // Kiểm tra xem someObject TextReader, // hay dẫn xuất từ TextReader toán tử is if (someObject is System.IO.TextReader) { // Làm § } Cả hai cách địi hỏi kiểu dùng với tốn tử typeof is phải kiểu biết khả phân giải lúc biên dịch Một cách khác linh hoạt (nhưng chậm hơn) sử dụng phương thức Type.GetType để trả tham chiếu Type cho kiểu định Tham chiếu Type không phân giải thực thi, việc ảnh hưởng đến hiệu năng, cho phép bạn thay đổi phép so sánh kiểu lúc thực thi dựa giá trị chuỗi Phương thức IsType trả true đối tượng thuộc kiểu định sử dụng phương thức Type.IsSubclassOf để kiểm tra đối tượng có phải lớp kiểu định hay không public static bool IsType(object obj, string type) { Type t = Type.GetType(type, true, true); return t == obj.GetType() || obj.GetType().IsSubclassOf(t); } Cuối cùng, bạn sử dụng toán tử as để ép đối tượng sang kiểu định Nếu đối tượng bị ép sang kiểu định, toán tử as trả null Điều cho phép bạn thực phép ép kiểu an toàn (safe cast), kiểu so sánh phải khả phân giải lúc thực thi Dưới ví dụ: // Sử dụng toán tử as để thực phép ép kiểu an toàn StringReader reader = someObject as System.IO.StringReader; if (reader != null) { // Làm § } Phương thức tĩnh GetUnderlyingType lớp System.Enum cho phép bạn thu lấy kiểu thực kiểu liệt kê 3.12 Tạo đối tượng chế phản chiếu Bạn cần tạo đối tượng chế phản chiếu 92 Chương 3: Miền ứng dụng, chế phản chiếu, siêu liệu Thu lấy đối tượng Type mô tả kiểu đối tượng cần tạo, gọi phương thức GetConstructor để có đối tượng System.Reflection.ConstructorInfo mô tả phương thức khởi dựng cần dùng, sau thực thi phương thức ConstructorInfo.Invoke Bước việc tạo đối tượng chế phản chiếu thu lấy đối tượng Type mô tả kiểu đối tượng cần tạo (xem mục 3.10 để biết thêm chi tiết) Khi có đối tượng Type, gọi phương thức GetConstructor để thu lấy đối tượng ConstructorInfo mô tả phương thức khởi dựng kiểu Dạng thức thông dụng phương thức GetConstructor nhận mảng Type làm đối số, trả đối tượng ConstructorInfo mô tả phương thức khởi dựng nhận đối số định mảng Type Để thu lấy đối tượng ConstructorInfo mô tả phương thức khởi dựng mặc định (khơng có đối số), bạn truyền cho phương thức GetConstructor mảng Type rỗng (sử dụng trường tĩnh Type.EmptyTypes); đừng sử dụng null, không GetConstructor ném ngoại lệ System.ArgumentNullException Nếu GetConstructor không tìm thấy phương thức khởi dựng có chữ ký phù hợp với đối số định trả null Mơt có đối tượng ConstructorInfo mong muốn, gọi phương thức Invoke Bạn phải cung cấp mảng chứa đối số mà bạn muốn truyền cho phương thức khởi dựng Phương thức Invoke tạo đối tượng trả tham chiếu đến đối tượng (bạn phải ép kiểu phù hợp) Dưới đoạn mã trình bày cách tạo đối tượng System.Text.StringBuilder, định nội dung ban đầu cho StringBuilder sức chứa // Thu lấy đối tượng Type cho lớp StringBuilder Type type = typeof(System.Text.StringBuilder); // Tạo Type[] chứa đối tượng Type cho đối số // phương thức khởi dựng (một chuỗi số nguyên) Type[] argTypes = new Type[] {typeof(System.String), typeof(System.Int32)}; // Thu lấy đối tượng ConstructorInfo ConstructorInfo cInfo = type.GetConstructor(argTypes); // Tạo object[] chứa đối số cho phương thức khởi dựng object[] argVals = new object[] {"Some string", 30}; // Tạo đối tượng ép kiểu StringBuilder StringBuilder sb = (StringBuilder)cInfo.Invoke(argVals); Chức phản chiếu thường sử dụng để thực factory Trong đó, bạn sử dụng chế phản chiếu để thể hóa lớp thừa kế lớp sở phổ biến hay thực giao diện phổ biến Thông thường, lớp sở chung giao diện chung sử dụng Lớp sở trừu tượng thực giao diện chức chung nào, sau thực cụ thể thừa kế lớp sở Không có chế để khai báo lớp cụ thể phải thực phương thức khởi dựng với chữ ký cụ thể Nếu muốn người khác (hãng thứ ba) thực lớp cụ thể bạn phải rõ (trong tài liệu hướng dẫn) chữ ký phương thức khởi dựng mà factory bạn gọi Cách thông thường để tránh vấn đề sử dụng phương thức khởi dựng mặc định (khơng có đối số), sau cấu hình đối tượng phương thức thuộc tính Ví dụ thực factory dùng để tạo đối tượng có thực giao diện IPlugin 93 Chương 3: Miền ứng dụng, chế phản chiếu, siêu liệu using System; using System.Reflection; // Giao diện chung mà tất plug-in phải thực public interface IPlugin { string Description { get; set; } void Start(); void Stop(); } // Lớp sở trừu tượng mà tất plug-in phải dẫn xuất từ public abstract class AbstractPlugin : IPlugin { // Chuỗi chứa lời mô tả plug-in private string description = ""; // Thuộc tính dùng để lấy lời mô tả plug-in public string Description { get { return description; } set { description = value; } } // Khai báo thành viên giao diện IPlugin public abstract void Start(); public abstract void Stop(); } // Một thực đơn giản cho giao diện IPlugin // để minh họa lớp PluginFactory public class SimplePlugin : AbstractPlugin { // Hiện thực phương thức Start public override void Start() { Console.WriteLine(Description } + ": Starting "); // Hiện thực phương thức Stop public override void Stop() { Console.WriteLine(Description + ": Stopping "); } } // Factory dùng để tạo đối tượng IPlugin public sealed class PluginFactory { public static IPlugin CreatePlugin(string assembly, string pluginName, string description) { // Thu lấy đối tượng Type cho plug-in định Type type = Type.GetType(pluginName + ", " + assembly); // Thu lấy đối tượng ConstructorInfo ConstructorInfo cInfo = type.GetConstructor(Type.EmptyTypes); // Tạo đối tượng ép kiểu StringBuilder IPlugin plugin = (IPlugin)cInfo.Invoke(null); // Cấu hình IPlugin plugin.Description = description; return plugin; } } Câu lệnh sau tạo đối tượng SimplePlugin lớp PluginFactory: 94 Chương 3: Miền ứng dụng, chế phản chiếu, siêu liệu IPlugin plugin = PluginFactory.CreatePlugin( "CreateObjectExample", // Tên assembly "SimplePlugin", // Tên lớp plug-in "A Simple Plugin" // Lời mô tả plug-in ); Lớp System.Activator cung cấp hai phương thức tĩnh CreateInstance CreateInstanceFrom dùng để tạo đối tượng dựa đối tượng Type hay chuỗi chứa tên kiểu Xem tài liệu NET Framework SDK để biết thêm chi tiết Tạo đặc tính tùy biến 3.13 Bạn cần tạo đặc tính theo ý bạn Tạo lớp dẫn xuất từ lớp sở trừu tượng System.Attribute Hiện thực phương thức khởi dựng, trường, thuộc tính phép người dùng cấu hình đặc tính Sử dụng System.AttributeUsageAttribute để định nghĩa: • Những phần tử chương trình đích đặc tính • Bạn áp dụng nhiều thể đặc tính cho phần tử chương trình hay khơng • Đặc tính có thừa kế kiểu dẫn xuất hay khơng Đặc tính cung cấp chế tổng quát cho việc kết hợp thông tin khai báo (siêu liệu) với phần tử chương trình Siêu liệu nằm assembly biên dịch, cho phép chương trình thu lấy thơng qua chế phản chiếu lúc thực thi (xem mục 3.14.) Các chương trình khác, đặc biệt CLR, sử dụng thông tin để xác định cách thức tương tác quản lý phần tử chương trình Để tạo đặc tính tùy biến dẫn xuất lớp từ lớp sở trừu tượng System.Attribute Các lớp đặc tính tùy biến phải public có tên kết thúc “Attribute” Một đặc tính tùy biến phải có phương thức khởi dựng công khai Các đối số phương thức khởi dựng trở thành đối số vị trí (positional parameter) đặc tính Như với lớp khác, bạn khai báo nhiều phương thức khởi dựng, cho phép người dùng tùy chọn sử dụng tập khác đối số vị trí áp dụng đặc tính Bất kỳ thuộc tính trường đọc/ghi cơng khai đặc tính khai báo trở thành đối số nêu tên (named parameter) Để điều khiển cách thức người dùng áp dụng đặc tính, áp dụng đặc tính AttributeUsageAttribute cho đặc tính tùy biến bạn Đặc tính AttributeUsageAttribute hỗ trợ đối số vị trí hai đối số nêu tên, mô tả bảng 3.3 Các giá trị mặc định định giá trị áp dụng cho đặc tính tùy biến bạn bạn không áp dụng AttributeUsageAttribute không định giá trị cho thông số Bảng 3.3 Các thành viên thuộc kiểu liệt kê AttributeUsage Thông số Kiểu Mô tả Mặc định 95 Chương 3: Miền ứng dụng, chế phản chiếu, siêu liệu Một thành viên thuộc kiểu liệt kê System.AttributeTargets, định ValidOn vị trí AllowMultiple nêu tên Đặc tính định nhiều lần cho phần tử hay không false Inherited nêu tên Đặc tính có thừa kế lớp dẫn xuất hay thành viên chép đè hay khơng true phần tử chương trình mà đặc tính có hiệu lực AttributeTargets.All Ví dụ trình bày cách tạo đặc tính tùy biến có tên AuthorAttribute, cho phép bạn xác định tên công ty người tạo lớp hay assembly AuthorAttribute khai báo phương thức khởi dựng công khai, nhận chuỗi chứa tên tác giả Điều yêu cầu người sử dụng AuthorAttribute phải cung cấp đối số vị trí chứa tên tác giả Company thuộc tính cơng khai (có thể dùng làm đối số nêu tên), Name thuộc tính chỉ-đọc (khơng thể dùng làm đối số nêu tên) using System; [AttributeUsage(AttributeTargets.Class | AttributeTargets.Assembly, AllowMultiple = true, Inherited = false)] public class AuthorAttribute : System.Attribute { private string company; // Công ty tác giả private string name; // Tên tác giả // Khai báo phương thức khởi dựng công khai public AuthorAttribute(string name) { this.name = name; company = ""; } // Khai báo thuộc tính Company có quyền set/get public string Company { get { return company; } set { company = value; } } // Khai báo thuộc tính Name chỉ-đọc public string Name{ get { return name;} } } Dưới cách sử dụng AuthorAttribute: // Khai báo Square Nguyen tác giả assembly [assembly:Author("Square Nguyen", Company = "Goldsoft Ltd.")] // Khai báo Square Nguyen tác giả lớp [Author("Square Nguyen", Company = "Goldsoft Ltd.")] public class SomeClass { § } 96 Chương 3: Miền ứng dụng, chế phản chiếu, siêu liệu // Khai báo Stephen Chow tác giả lớp [Author("Stephen Chow")] public class SomeOtherClass { § } Sử dụng chế phản chiếu để kiểm tra 3.14 đặc tính phần tử chương trình Bạn muốn sử dụng chế phản chiếu để kiểm tra đặc tính tùy biến áp dụng cho phần tử chương trình Gọi phương thức GetCustomAttributes đối tượng dẫn xuất từ lớp System.Reflection.MemberInfo (đối tượng mô tả phần tử chương trình cần kiểm tra) Tất lớp mơ tả phần tử chương trình dẫn xuất từ lớp MemberInfo Lớp bao gồm Type, EventInfo, FieldInfo, PropertyInfo, MethodBase MethodBase có thêm hai lớp con: ConstructorInfo MethodInfo Bạn gọi phương thức GetCustomAttributes có đối tượng lớp Phương thức trả mảng chứa đặc tính tùy biến áp dụng cho phần tử chương trình Chú ý mảng chứa đặc tính tùy biến khơng chứa đặc tính có sẵn thư viện lớp sở NET Framework Phương thức GetCustomAttributes có hai dạng thức Dạng nhận đối số bool để xác định phương thức có trả đặc tính thừa kế từ lớp cha hay khơng Dạng thứ hai nhận thêm đối số Type có vai trò lọc, kết trả đặc tính thuộc kiểu định Type Ví dụ sau sử dụng đặc tính tùy biến AuthorAttribute khai báo mục 3.13 áp dụng vào lớp GetCustomAttributesExample Phương thức Main gọi phương thức GetCustomAttributes, lọc đặc tính để kết trả AuthorAttribute Bạn thực ép kiểu an tồn đặc tính tham chiếu AuthorAttribute truy xuất thành viên chúng mà không cần sử dụng chế phản chiếu using System; [Author("Stephen Chau")] [Author("Square Nguyen", Company = "Goldsoft Ltd.")] public class GetCustomAttributesExample { public static void Main() { // Lấy đối tượng Type cho lớp Type type = typeof(GetCustomAttributesExample); // Lấy đặc tính cho kiểu Sử dụng lọc để // kết trả AuthorAttribute object[] attrs = type.GetCustomAttributes(typeof(AuthorAttribute), true); 97 Chương 3: Miền ứng dụng, chế phản chiếu, siêu liệu // Liệt kê đặc tính foreach (AuthorAttribute a in attrs) { Console.WriteLine(a.Name + ", " + a.Company); } // Nhấn Enter để kết thúc Console.ReadLine(); } } 98 Chương 4: TIỂU TRÌNH, TIẾN TRÌNH, VÀ SỰ ĐỒNG BỘ 99 100 Chương 4: Tiểu trình, tiến trình, đồng M ột điểm mạnh hệ điều hành Microsoft Windows cho phép nhiều chương trình (tiến trình—process) chạy đồng thời cho phép tiến trình thực nhiều tác vụ đồng thời (bằng nhiều tiểu trình—thread) Chương trình bày cách kiểm sốt tiến trình tiểu trình ứng dụng dựa vào tính thư viện lớp NET Framework cung cấp Các mục chương trình bày cách thực vấn đề sau: Sử dụng kỹ thuật tính khác NET Framework để tạo tiểu trình (mục 4.1 đến 4.5) Kiểm sốt q trình thực thi tiểu trình để biết kết thúc (mục 4.6 4.7) Đồng hóa q trình thực thi nhiều tiểu trình (mục 4.8 4.9) Chạy dừng tiến trình (mục 4.10 4.11) Bảo đảm thời điểm chạy thể ứng dụng (mục 4.12) 4.1 Thực thi phương thức với thread-pool Bạn cần thực thi phương thức tiểu trình thread-pool thực thi Khai báo phương thức chứa mã lệnh cần thực thi; phương thức phải trả void nhận đối số Sau đó, tạo thể ủy nhiệm System.Threading.WaitCallback tham chiếu đến phương thức Tiếp tục, gọi phương thức tĩnh QueueUserWorkItem lớp System.Threading.ThreadPool, truyền thể ủy nhiệm tạo làm đối số Bộ thực thi xếp thể ủy nhiệm vào hàng đợi thực thi tiểu trình thread-pool sẵn sàng Nếu ứng dụng sử dụng nhiều tiểu trình có thời gian sống ngắn hay trì số lượng lớn tiểu trình đồng thời hiệu giảm sút chi phí cho việc tạo, vận hành hủy tiểu trình Ngồi ra, hệ thống hỗ-trợ-đa-tiểu-trình, tiểu trình thường trạng thái rỗi suốt khoảng thời gian dài để chờ điều kiện thực thi phù hợp Việc sử dụng thread-pool cung cấp giải pháp chung nhằm cải thiện tính quy mơ hiệu hệ thống hỗ-trợ-đa-tiểu-trình .NET Framework cung cấp thực đơn giản cho thread-pool mà truy xuất thơng qua thành viên tĩnh lớp ThreadPool Phương thức QueueUserWorkItem cho phép bạn thực thi phương thức tiểu trình thread-pool (đặt cơng việc vào hàng đợi) Mỗi công việc mô tả thể ủy nhiệm WaitCallback (tham chiếu đến phương thức cần thực thi) Khi tiểu trình thread-pool sẵn sàng, nhận cơng việc từ hàng đợi thực thi cơng việc Khi hồn tất cơng việc, thay kết thúc, tiểu trình quay thread-pool nhận công việc từ hàng đợi Việc sử dụng thread-pool thực thi giúp đơn giản hóa việc lập trình hỗ-trợ-đa-tiểu-trình Tuy nhiên, cần lưu ý thread-pool thực đơn giản, nhằm mục đích sử dụng chung Trước định sử dụng thread-pool này, cần xem xét điểm sau: 101 Chương 4: Tiểu trình, tiến trình, đồng • Bộ thực thi quy định số tiểu trình tối đa cấp cho thread-pool; bạn thay đổi số tối đa tham số cấu hình hay từ bên mã được-quản-lý Giới hạn mặc định 25 tiểu trình cho CPU hệ thống Số tiểu trình tối đa thread-pool khơng giới hạn số công việc chờ hàng đợi • Cũng việc cho phép bạn sử dụng thread-pool để thực thi mã lệnh cách trực tiếp, thực thi cịn sử dụng thread-pool cho nhiều mục đích bên trong, bao gồm việc thực thi phương thức cách bất đồng (xem mục 4.2) thực thi kiện định thời (xem mục 4.3) Tất cơng việc dẫn đến tranh chấp tiểu trình thread-pool; nghĩa hàng đợi trở nên dài Mặc dù độ dài tối đa hàng đợi bị giới hạn số lượng nhớ cịn lại cho tiến trình thực thi, hàng đợi dài làm kéo dài q trình thực thi cơng việc hàng đợi • Bạn khơng nên sử dụng thread-pool để thực thi tiến trình chạy thời gian dài Vì số tiểu trình thread-pool có giới hạn, nên số tiểu trình thuộc tiến trình loại ảnh hưởng đáng kể đến toàn hiệu threadpool Đặc biệt, bạn nên tránh đặt tiểu trình thread-pool vào trạng thái đợi thời gian dài • Bạn khơng thể điều khiển lịch trình tiểu trình thread-pool, khơng thể thay đổi độ ưu tiên công việc Thread-pool xử lý công việc theo thứ tự bạn thêm chúng vào hàng đợi • Một cơng việc đặt vào hàng đợi bạn khơng thể hủy hay dừng Ví dụ trình bày cách sử dụng lớp ThreadPool để thực thi phương thức có tên DisplayMessage Ví dụ truyền DisplayMessage đến thread-pool hai lần, lần đầu khơng có đối số, lần sau có đối số đối tượng MessageInfo (cho phép kiểm sốt thơng tin mà tiểu trình hiển thị) using System; using System.Threading; // Lớp dùng để truyền liệu cho phương thức DisplayMessage // thực thi thread-pool public class MessageInfo { private int iterations; private string message; // Phương thức khởi dựng nhận thiết lập cấu hình cho tiểu trình public MessageInfo(int iterations, string message) { this.iterations = iterations; this.message = message; } // Các thuộc tính dùng để lấy thiết lập cấu hình public int Iterations { get { return iterations; } } public string Message { get { return message; } } } public class ThreadPoolExample { // Hiển thị thông tin cửa sổ Console 102 Chương 4: Tiểu trình, tiến trình, đồng public static void DisplayMessage(object state) { // Ép đối số state sang MessageInfo MessageInfo config = state as MessageInfo; // // // if Nếu đối số config null, khơng có đối số truyền cho phương thức ThreadPool.QueueUserWorkItem; sử dụng giá trị mặc định (config == null) { // Hiển thị thông báo cửa sổ Console ba lần for (int count = 0; count < 3; count++) { Console.WriteLine("A thread-pool example."); // Vào trạng thái chờ, dùng cho mục đích minh họa // Tránh đưa tiểu trình thread-pool // vào trạng thái chờ ứng dụng thực tế Thread.Sleep(1000); } } else { // Hiển thị thông báo định trước // với số lần định trước for (int count = 0; count < config.Iterations; count++) { Console.WriteLine(config.Message); // Vào trạng thái chờ, dùng cho mục đích minh họa // Tránh đưa tiểu trình thread-pool // vào trạng thái chờ ứng dụng thực tế Thread.Sleep(1000); } } } public static void Main() { // Tạo đối tượng ủy nhiệm, cho phép // truyền phương thức DisplayMessage cho thread-pool WaitCallback workMethod = new WaitCallback(ThreadPoolExample.DisplayMessage); // Thực thi DisplayMessage thread-pool (khơng có đối số) ThreadPool.QueueUserWorkItem(workMethod); // Thực thi DisplayMessage thread-pool (truyền // đối tượng MessageInfo cho phương thức DisplayMessage) MessageInfo info = new MessageInfo(5, "A thread-pool example with arguments."); ThreadPool.QueueUserWorkItem(workMethod, info); // Nhấn Enter để kết thúc Console.WriteLine("Main method complete Press Enter."); Console.ReadLine(); } } 103 Chương 4: Tiểu trình, tiến trình, đồng 4.2 Thực thi phương thức cách bất đồng Bạn cần thực thi phương thức tiếp tục thực công việc khác phương thức chạy tiểu trình riêng biệt Sau phương thức hồn tất, bạn cần lấy trị trả Khai báo ủy nhiệm có chữ ký giống phương thức cần thực thi Sau đó, tạo thể ủy nhiệm tham chiếu đến phương thức Tiếp theo, gọi phương thức BeginInvoke thể ủy nhiệm để thực thi phương thức bạn Kế đến, sử dụng phương thức EndInvoke để kiểm tra trạng thái phương thức thu lấy trị trả hồn tất Khi cho gọi phương thức, thường thực cách đồng bộ; nghĩa mã lệnh thực lời gọi phải vào trạng thái dừng (block) phương thức thực xong Đây cách cần thiết mã lệnh yêu cầu trình thực thi phương thức phải hồn tất trước tiếp tục Tuy nhiên, số trường hợp, bạn lại cần thực thi phương thức cách bất đồng bộ; nghĩa bạn cho thực thi phương thức tiểu trình riêng tiếp tục thực công việc khác .NET Framework hỗ trợ chế độ thực thi bất đồng bộ, cho phép bạn thực thi phương thức cách bất đồng ủy nhiệm Khi khai báo biên dịch ủy nhiệm, trình biên dịch tự động sinh hai phương thức hỗ trợ chế độ thực thi bất đồng bộ: BeginInvoke EndInvoke Khi bạn gọi phương thức BeginInvoke thể ủy nhiệm, phương thức tham chiếu ủy nhiệm xếp vào hàng đợi để thực thi bất đồng Quyền kiểm sốt q trình thực thi trả cho mã gọi BeginInvoke sau đó, phương thức tham chiếu thực thi ngữ cảnh tiểu trình sẵn sàng trước tiên thread-pool Các đối số phương thức BeginInvoke gồm đối số định ủy nhiệm, cộng với hai đối số dùng phương thức thực thi bất đồng kết thúc Hai đối số là: • Một thể ủy nhiệm System.AsyncCallback tham chiếu đến phương thức mà thực thi gọi phương thức thực thi bất đồng kết thúc Phương thức thực thi ngữ cảnh tiểu trình thread-pool Truyền giá trị null cho đối số nghĩa khơng có phương thức gọi bạn phải sử dụng chế khác để xác định phương thức thực thi bất kết thúc (sẽ thảo luận bên dưới) • Một tham chiếu đối tượng mà thực thi liên kết với trình thực thi bất đồng Phương thức thực thi bất đồng sử dụng hay truy xuất đến đối tượng này, mã lệnh bạn sử dụng phương thức kết thúc, cho phép bạn liên kết thông tin trạng thái với q trình thực thi bất đồng Ví dụ, đối tượng cho phép bạn ánh xạ kết với thao tác bất đồng khởi tạo trường hợp bạn khởi tạo nhiều thao tác bất đồng sử dụng chung phương thức callback để xử lý việc kết thúc Phương thức EndInvoke cho phép bạn lấy trị trả phương thức thực thi bất đồng bộ, trước hết bạn phải xác định kết thúc Dưới bốn kỹ thuật dùng để xác định phương thức thực thi bất đồng kết thúc hay chưa: 104 Chương 4: Tiểu trình, tiến trình, đồng • Blocking—dừng q trình thực thi tiểu trình hành phương thức thực thi bất đồng kết thúc Điều giống với thực thi đồng Tuy nhiên, linh hoạt chọn thời điểm xác để đưa mã lệnh bạn vào trạng thái dừng (block) bạn cịn hội thực thêm số việc trước mã lệnh vào trạng thái • Polling—lặp lặp lại việc kiểm tra trạng thái phương thức thực thi bất đồng để xác định kết thúc hay chưa Đây kỹ thuật đơn giản, xét mặt xử lý khơng hiệu Bạn nên tránh vòng lặp chặt làm lãng phí thời gian xử lý; tốt nên đặt tiểu trình thực polling vào trạng thái nghỉ (sleep) khoảng thời gian cách sử dụng Thread.Sleep lần kiểm tra trạng thái Bởi kỹ thuật polling địi hỏi bạn phải trì vịng lặp nên hoạt động tiểu trình chờ bị giới hạn, nhiên bạn dễ dàng cập nhật tiến độ cơng việc • Waiting—sử dụng đối tượng dẫn xuất từ lớp System.Threading.WaitHandle để báo hiệu phương thức thực thi bất đồng kết thúc Waiting cải tiến kỹ thuật polling, cho phép bạn chờ nhiều phương thức thực thi bất đồng kết thúc Bạn định giá trị time-out cho phép tiểu trình thực waiting dừng lại phương thức thực thi bất đồng diễn lâu, bạn muốn cập nhật định kỳ trạng thái • Callbacks—Callback phương thức mà thực thi gọi phương thức thực thi bất đồng kết thúc Mã lệnh thực lời gọi không cần thực thao tác kiểm tra nào, tiếp tục thực công việc khác Callback linh hoạt phức tạp, đặc biệt có nhiều phương thức thực thi bất đồng chạy đồng thời sử dụng callback Trong trường hợp thế, bạn phải sử dụng đối tượng trạng thái thích hợp để so trùng phương thức hoàn tất với phương thức khởi tạo Lớp AsyncExecutionExample ví dụ mơ tả chế thực thi bất đồng Nó sử dụng ủy nhiệm có tên AsyncExampleDelegate để thực thi bất đồng phương thức có tên LongRunningMethod Phương thức LongRunningMethod sử dụng Thread.Sleep để mô phương thức có thời gian thực thi dài // Ủy nhiệm cho phép bạn thực việc thực thi bất đồng // AsyncExecutionExample.LongRunningMethod public delegate DateTime AsyncExampleDelegate(int delay, string name); // Phương thức có thời gian thực thi dài public static DateTime LongRunningMethod(int delay, string name) { Console.WriteLine("{0} : {1} example - thread starting.", DateTime.Now.ToString("HH:mm:ss.ffff"), name); // Mô việc xử lý tốn nhiều thời gian Thread.Sleep(delay); Console.WriteLine("{0} : {1} example - thread finishing.", DateTime.Now.ToString("HH:mm:ss.ffff"), name); // Trả thời gian hoàn tất phương thức return DateTime.Now; } 105 Chương 4: Tiểu trình, tiến trình, đồng AsyncExecutionExample chứa năm phương thức diễn đạt cách tiếp cận khác việc kết thúc phương thức thực thi bất đồng Dưới mô tả cung cấp mã lệnh cho phương thức Phương thức BlockingExample Phương thức BlockingExample thực thi bất đồng phương thức LongRunningMethod tiếp tục thực cơng việc khoảng thời gian Khi xử lý xong công việc này, BlockingExample chuyển sang trang thái dừng (block) phương thức LongRunningMethod kết thúc Để vào trạng thái dừng, BlockingExample thực thi phương thức EndInvoke thể ủy nhiệm AnsyncExampleDelegate Nếu phương thức LongRunningMethod kết thúc, EndInvoke trả lập tức, không, BlockingExample chuyển sang trạng thái dừng phương thức LongRunningMethod kết thúc public static void BlockingExample() { Console.WriteLine(Environment.NewLine + "*** Running Blocking Example ***"); // Gọi LongRunningMethod cách bất đồng Truyền null cho // ủy nhiệm callback đối tượng trạng thái bất đồng AsyncExampleDelegate longRunningMethod = new AsyncExampleDelegate(LongRunningMethod); IAsyncResult asyncResult = longRunningMethod.BeginInvoke(2000, "Blocking", null, null); // Thực công việc khác // sẵn sàng vào trạng thái dừng for (int count = 0; count < 3; count++) { Console.WriteLine("{0} : Continue processing until " + "ready to block ", DateTime.Now.ToString("HH:mm:ss.ffff")); Thread.Sleep(200); } // Đi vào trạng thái dừng phương thức // thực thi bất đồng kết thúc thu lấy kết Console.WriteLine("{0} : Blocking until method is " + "complete ", DateTime.Now.ToString("HH:mm:ss.ffff")); DateTime completion = longRunningMethod.EndInvoke(asyncResult); // Hiển thị thông tin kết thúc Console.WriteLine("{0} : Blocking example complete.", completion.ToString("HH:mm:ss.ffff")); } Phương thức PollingExample Phương thức PollingExample thực thi bất đồng phương thức LongRunningMethod sau thực vịng lặp polling LongRunningMethod kết thúc PollingExample kiểm tra thuộc tính IsComplete thể IAsyncResult (được trả BeginInvoke) để xác định phương thức LongRunningMethod kết thúc hay chưa, chưa, PollingExample gọi Thread.Sleep ... assembly biên dịch, cho phép chương trình thu lấy thơng qua chế phản chiếu l? ?c th? ?c thi (xem m? ?c 3.14.) C? ?c chương trình kh? ?c, đ? ?c biệt CLR, sử dụng thơng tin để x? ?c định c? ?ch th? ?c tương t? ?c quản lý... th? ?c ICollection.CopyTo (đư? ?c th? ?c tất lớp tập hợp), sử dụng phương th? ?c ToArray (đư? ?c th? ?c tập hợp ArrayList, Stack, Queue) C? ?c phương th? ?c ICollection.CopyTo ToArray c? ? ch? ?c năng, chúng chép... (bằng nhiều tiểu trình? ??thread) Chương trình bày c? ?ch kiểm sốt tiến trình tiểu trình ứng dụng dựa vào tính thư viện lớp NET Framework cung c? ??p C? ?c m? ?c chương trình bày c? ?ch th? ?c vấn đề sau: Sử

Ngày đăng: 10/05/2021, 23:54