intTypePromotion=1
zunia.vn Tuyển sinh 2024 dành cho Gen-Z zunia.vn zunia.vn
ADSENSE

Tài Liệu Học Ngôn Ngữ Lập Trình C#_p9

Chia sẻ: Tailieu Upload | Ngày: | Loại File: PDF | Số trang:40

85
lượt xem
19
download
 
  Download Vui lòng tải xuống để xem tài liệu đầy đủ

Tham khảo tài liệu 'tài liệu học ngôn ngữ lập trình c#_p9', công nghệ thông tin, kỹ thuật lập trình phục vụ nhu cầu học tập, nghiên cứu và làm việc hiệu quả

Chủ đề:
Lưu

Nội dung Text: Tài Liệu Học Ngôn Ngữ Lập Trình C#_p9

  1. Ngôn Ngữ Lập Trình C# public static void Main() { Image theImage = new Image(); // do không có GUI để thực hi ện chúng ta sẽ ch ọn l ần // lượt các hành động và thực hi ện ImageProcessor theProc = new ImageProcessor(theImage); theProc.AddToEffects(theProc.BlurEffect); theProc.AddToEffects(theProc.FilterEffect); theProc.AddToEffects(theProc.RotateEffect); theProc.AddToEffects(theProc.SharpenEffect); theProc.ProcessImage(); } } } -----------------------------------------------------------------------------  Kết quả: An image created Blurring image Filtering image Rotate image Sharpening image ----------------------------------------------------------------------------- Trong ví dụ trên, đố i tượng ImageProcessor được tạo ra và những hiệu ứng đ ược thêm vào. Nếu người dùng chọn làm mờ trước khi lọc ảnh, thì đ ơn giản là đ ược đ ưa vào mảng ủ y quyền theo thứ tự tương ứ ng. Tương tự như vậ y, b ất cứ hành đ ộng lựa chọ n nào củ a người dù ng mong muốn, ta đ ưa thêm nhiều ủ y quyền vào trong tập hợp. Chúng ta có thể tưởng tượng việc hiển thị thứ tự hành độ ng này trong một danh sách listbox và cho phép người sử dụng sắp xếp lại phương thức, di chuyển chú ng lên xuố ng trong danh sách. Khi các hành độ ng nà y được sắp xếp lại thì chúng ta chỉ cần thay đ ổi thứ tự trong tập hợp. Ngo ài ra ta cũng có thể đ ưa các hoạt động này vào trong cơ sở d ữ liệu rồ i sau đó đọ c chú ng lú c thực hiện. Ủ y quyền dễ d àng cung cấp động cho ta các phương thứ c được gọ i theo một thứ tự xác đ ịnh Multicasting Cơ chế multicasting cho phép gọi hai phương thức thực thi thông qua mộ t ủ y quyền đ ơn. Điều nà y trở nên quan trọng khi xử lý các sự kiện, sẽ được thảo lu ận trong phần cuối củ a chương. 321 Cơ Chế Ủy Quyền - Sự Kiện
  2. Ngôn Ngữ Lập Trình C# Mụ c đích chính là có một ủ y quyền có thể gọ i thực hiện nhiều hơn mộ t phương thức. Điều này ho àn toàn khác với việc có một tập hợp các ủ y quyền, vì mỗ i trong số chúng chỉ gọi đ ược duy nhất một phương thứ c. Trong ví dụ trước, tập hợp đ ược sử dụ ng đ ể lưu giữ các ủ y quyền khác nhau. Tập hợp này cũ ng có thể thêm một ủ y quyền nhiều hơn một lần, và sử dụng tập hợp để sắp xếp lại các ủ y quyền và đ iều khiển thứ tự hành độ ng được gọi. Với Multicasting chúng ta có thể tạo một ủ y quyền đ ơn và cho phép gọ i nhiều phương thứ c được đóng. Ví dụ, khi một nút lệnh được nhấn chúng ta có thể muốn thực hiện nhiều hơn một hàh độ ng. Để làm được đ iều này chú ng ta có thể đưa cho button mộ t tập hợp các ủ y quyền, nhưng để sáng rõ hơn và dễ d àng hơn là tạo một ủy quyền Multicast. Bất cứ ủ y quyền nào trả về giá trị void là ủ y quyền multicast, mặc dù vậy ta có thể đối xử với nó như là ủ y quyền b ình thườ ng cũ ng khô ng sao. Hai ủ y quyền Multicast có thể đ ược kết hợp với nhau bằng phép toán cộ ng (+). Kết qu ả là một ủ y quyền Multicast mới và gọi đến tất cả các phương thức thực thi nguyên thủ y củ a cả hai bên. Ví d ụ, giả sử Writer và Logger là ủ y quyền trả về giá trị void, dò ng lệnh theo sau sẽ kết hợp chúng lại với nhau và tạo ra một ủ y quyền Multicast mới: myMulticastDelegate = Writer + Logger; Chúng ta cũ ng có thể thêm những ủ y quyền vào trong ủ y quyền Multicast bằng to án tử cộng bằng (+=). Phép toán nà y sẽ thêm ủ y quyền ở phía bên phải củ a toán tử vào ủ y quyền Multicast ở bên trái. Ví dụ minh họ a như sau, giả sử có Transmitter và myMulticastDelegate là những ủ y quyền, lệnh tiếp theo sau đ ây sẽ thực hiện việc thêm ủ y quyền Transmitter vào trong myMulticastDelegate: myMulticastDelegate += Transmitter; Để hiểu rõ ủy quyền Multicast được tạo ra và sử dụng, chúng ta sẽ từng b ước tìm hiểu thông qua ví dụ 11.3 b ên dưới, trong ví dụ minh họa này chú ng ta sẽ tạo ra một lớp có tên gọi là MyClassWithDelegate lớp này định nghĩa một delegate, delegate nà y lấy một tham số là chu ỗi và khô ng có giá trị trả về: void delegate void StringDelegate( string s); Sau đó chú ng ta định một lớp gọ i là MyImplementingClass lớp này có ba phương thức, tất cả các phương thức này đ ều trả về giá trị void và nhận mộ t chuỗi làm tham số: WriteString, LogString, và Transmitting. Phương thức đ ầu tiên viết mộ t chuỗi xu ất ra màn hì nh tiêu chu ẩn, chuỗi thứ hai mô p hỏ ng viết vào mộ t log file, và phương thức thứ ba mô phỏng việc chuyển mộ t chuỗi qua Internet. Chú ng ta tạo thể hiện delegate để gọi những phương thức tương ứ ng: Writer(“String passed to Writer\n”); Logger(“String passed to Logger\n”); Transmitter(“String passed to Transmitter\n”); Để xem cách kết hợp các delegate, chúng ta tạo một thể hiện delegate khác: MyClassWithDelegate.StringDelegate myMulticastDelegate; 322 Cơ Chế Ủy Quyền - Sự Kiện
  3. Ngôn Ngữ Lập Trình C# và gán cho delegate nà y kết quả của phép cộ ng hai delegate cho trước: myMulticastDelegate = Writer + Logger; Tiếp theo chúng ta thêm vào delegate này một delegate nữa bằng cách sử dụng toán tử (+=): myMulticastDelegate += Transmitter; Cuối cù ng, chú ng ta thực hiện việc xóa deleagate bằng sử d ụng toán tử (-=): DelegateCollector -= Logger; Sau đây là toàn bộ ví dụ minh họa.  Ví dụ 11.3: Kết hợp các delegate. ----------------------------------------------------------------------------- namespace Programming_CSharp { using System; public class MyClassWithDelegate { // khai báo delegate public delegate void StringDelegate(string s); } public class MyImplementingClass { public static void WriteString( string s) { Console.WriteLine(“Writing string {0}”, s); } public static void LogString( string s) { Console.WriteLine(“Logging string {0}”, s); } public static void TransmitString( string s) { Console.WriteLine(“Transmitting string {0}”, s); } } public class Test { public static void Main() { // định nghĩ a 3 StringDelegate MyClassWithDelegate.StringDelegate Writer, Logger, Transmitter; 323 Cơ Chế Ủy Quyền - Sự Kiện
  4. Ngôn Ngữ Lập Trình C# // định nghĩ a một StringDelegate khác thực hi ện Multicasting MyClassWithDelegate.StringDelegate myMulticastDelegate; // tạo thể hiện của 3 delegate đầu ti ên và truyền vào phương thức thực thi Writer = new MyClassWithDelegate.StringDelegate( MyImplementingClass.WriteString); Logger = new MyClassWithDelegate.StringDelegate( MyImplementingClass.LogString); Transmitter = new MyClassWithDelegate.StringDelegate( MyImplementingClass.TransmitString); // gọi phương thức delegate Writer Writer(“String passed to Writer\n”); // gọi phương thức delegate Logger Logger(“String passed to Logger\n”); //gọi phương thức delegate Transmitter Transmitter(“String passed to Transmitter\n”); // thông báo người dùng rằng đã kết hợp hai delegate vào // trong một multicast delegate Console.WriteLine(“myMulticastDelegate = Writer + Logger”); // kết hợp hai delegate myMulticastDelegate = Writer + Logger; // gọi phương thức delegate, hai phương thức sẽ được thực hi ện myMulticastDelegate(“First string passed to Collector”); // bảo với người sử dụng rằng đã thêm delegate thứ 3 vào // trong Multicast delegate Console.WriteLine(“\nmyMulticastDeleagte += Transmitter”); // thêm delegate thứ ba vào myMulticastDelegate += Transmitter; // gọi thực thi Multicast delegate, cùng một lúc ba // phương thức sẽ cùng được gọi thực hi ện myMulticastDelegate(“Second string passed to Collector”); // bảo với người sử dụng rằng xóa delegate Logger Console.WriteLine(“\nmyMulticastDelegate -= Logger”); // xóa delegate Logger myMulticastDelegate -= Logger; // gọi l ại delegate, lúc này chỉ còn thực hiện hai phương thức myMulticastDelegate(“Third string passed to Collector”); }// end Main }// end class 324 Cơ Chế Ủy Quyền - Sự Kiện
  5. Ngôn Ngữ Lập Trình C# }// end namespace -----------------------------------------------------------------------------  Kết quả: Writing string String passed to Writer Logging string String passed to Logger Transmitting string String passed to Transmitter myMulticastDelegate = Writer + Logger Writing string First string passed to Collector Logging string First string passed to Collector myMulticastDelegate += Transmitter Writing string Second string passed to Collector Logging string Second string passed to Collector Transmitting string Second string passed to Collector myMulticastDelegate -= Logger Writing string Third string passed to Collector Transmitting string Third string passed to Collector ----------------------------------------------------------------------------- Trong ví dụ trên, những thể hiện delegate được định nghĩa và ba delegate đ ầu tiên Writer, Logger, và Transmitter được gọi ra. Delegate thứ tư myMulticastDelegate đ ược gán b ằng cách kết hợp hai delegate đầu, và khi nó đ ược gọi, thì d ẫn đến là cả hai delegate cũ ng được gọi. Khi delegate thứ b a đ ược thêm vào, và kết quả là khi myMulticastDelegate đ ược gọ i thì tất cả ba phương thức delegate cũ ng được thực hiện. Cuối cùng, khi Logger được xó a khỏi delegate, và khi myMulticastDelegate đ ược gọi thì chỉ có hai phương thứ c thực thi. Multicast delegate đ ược thể hiện tố t nhất trong việc ứng dụng xử lý các sự kiện. Khi một sự kiện ví dụ như một nút lệnh được nhấn, thì một multicast delegate tương ứ ng sẽ gọ i đến một lo ạt các phương thức xử lý sự kiện để đ áp ứng lại với các sự kiện này. Sự kiện Trong mô i trường giao diện đ ồ họ a (Graphical User Interfaces: GUIs), Windows hay trong trình duyệt web đòi hỏ i các chương trình phải đ áp ứng các sự kiện. Mộ t sự kiện có thể là một nú t lệnh đ ược nhấn, một mụ c trong menu được chọn, hành động sao chép tập tin hoàn thành,...Hay nó i ngắn gọn là một hành đ ộng nào đó xả y ra, và ta phải đ áp ứng lại sự kiện đó . Chúng ta khô ng thể đo án trước được khi nào thì các sự kiện sẽ xuất hiện. Hệ thống sẽ chờ cho đến khi nhận được sự kiện, và sẽ chuyển vào cho trình xử lý sự kiện thực hiện. Trong môi trường giao diện đồ họa, b ất cứ thành phần nào cũng có thể đưa ra sự kiện. Ví dụ, khi chúng ta kích vào mộ t nút lệnh, nó có thể đ ưa ra sự kiện Click. Khi chúng ta thêm mộ t mục vào danh sách, nó sẽ đưa ra sự kiện ListChanged. 325 Cơ Chế Ủy Quyền - Sự Kiện
  6. Ngôn Ngữ Lập Trình C# Cơ chế publishing và subscribing Trong ngô n ngữ C#, b ất cứ đối tượng nào cũ ng có thể p ublish mộ t tập hợp các sự kiện đ ể cho các lớp khác có thể đ ăng ký . Khi một lớp publish đ ưa ra mộ t sự kiện, thì tất cả các lớp đã đăng ký sẽ đ ược nhận sự cảnh b áo. Ghi chú: Tác giả Gamma (Addison Wesley, 1995) mô tả cơ chế nà y như sau: “Định nghĩa một đến nhiều sự phụ thuộc giữa những đố i tượng do đó khi mộ t đối tượng thay đổ i trạng thái, tấ t cả cá c đối tượng khá c phụ thuộc vào nó sẽ được cảnh báo và cập nhật mộ t cách tự động”. Với cơ chế này, đối tượng của chú ng ta có thể nói rằng “Ở đây có những thứ mà tô i có thể thông báo cho bạn ” và những lớp khác có thể đăng ký đ áp rằng “Vâng, hã y báo cho tôi biết khi chuyện đó xả y ra”. Ví dụ, một nú t lệnh có thể cảnh báo cho b ất cứ thành phần nào khi nó được nhấn. Nút lệnh nà y được gọ i là publisher bởi vì nó phân phát sự kiện Click và nhữ ng lớp khác là các lớp subscriber vì chúng đ ăng ký nhận sự kiện Click nà y. Sự kiện và delegate Những sự kiện trong C# được thực thi với nhữ ng delegate. Lớp publisher định nghĩa một delegate và những lớp subscriber phải thực thi. Khi mộ t sự kiện xu ất hiện thì p hương thức của lớp subscriber đ ược gọ i thông qua delegate. Mộ t phương thức đ ược dùng để xử lý các sự kiện thì đ ược là trình xử lý sự kiện (event handler). Chú ng ta có thể khai báo trình xử lý sự kiện này như chúng ta đã làm với b ất cứ delegate khác. Theo quy ước, những trình xử lý sự kiện trong .NET Framework trả về giá trị void và lấy hai tham số . Tham số đầu tiên là nguồ n d ẫn đ ến sự kiện, đ ây chính là đố i tượng publisher. Và tham số thứ hai là đố i tượng d ẫn xuất từ lớp EventArgs. Yêu cầu chúng ta phải thự c hiện trình xử lý sự kiện theo mẫu như trên. EventArgs là lớp cơ sở cho tất cả các dữ liệu về sự kiện, lớp EventArgs thừa kế tất cả các phương thức của nó từ Object, và thêm vào một trường public static empty thể hiện một sự kiện khô ng có trạng thái (cho phép sử dụ ng hiệu quả nhữ ng sự kiện khô ng trạng thái). Lớp dẫn xu ất từ EventArgs chứa những thông tin về sự kiện. Sự kiện là thuộ c tính của lớp phát ra sự kiện. Từ khó a event điều khiển cách thu ộc tính sự kiện đ ược truy cập bởi các lớp subscriber. Từ khóa event được thiết kế đ ể duy trì cho cách thể hiện publish/ subscribe. Giả sử chúng ta muốn tạo mộ t lớp Clock dù ng những sự kiện đ ể cảnh b áo những lớp subscriber bất cứ khi nào đồng hồ hệ thống thay đổ i giá trị trong một giâ y. Gọi sự kiện này là OnSecondChange. Chúng ta khai báo sự kiện và kiểu delegate xử lý sự kiện củ a nó như sau: [attributes] [modifiers] event type member- name Ví dụ khai báo như sau: 326 Cơ Chế Ủy Quyền - Sự Kiện
  7. Ngôn Ngữ Lập Trình C# public event SecondChangeHandler OnSecondChange; Trong ví dụ này ta khô ng dù ng thuộ c tính, modifier ở đ ây là abstract, new, override, static, virtual, hay là một trong bốn access modifier, trong trường hợp này public. Modifier được theo sau bởi từ khóa event. Trường type trong trường hợp ví dụ này là d elegate mà chú ng ta muố n liên hệ với sự kiện, ở đây là SecondChangeHandler. Tên thành viên là tên của sự kiện, trong trường hợp nà y là OnSecondChange. Thô ng thườ ng, tên sự kiện b ắt đầu với từ On. Tóm lại, trong sự khai báo này OnSecondChange là sự kiện được thực thi b ởi delegate có kiểu là SecondChangeHandler. Ta có khai báo cho delegate nà y như sau: public delegate void SecondChangeHandler( object clock, TimeInfoEventArgs ti meInformation); Như đã nói trước đây, theo quy ước mộ t trình xử lý sự kiện phải trả về giá trị void và p hải lấy hai tham số: nguồ n phát ra sự kiện (trong trường hợp này là clock) và một đố i tượng d ẫn xuất từ EventArgs, là TimeInfoEventArgs. Lớp TimeInfoEventArgs đ ược định nghĩa như sau: public class TimeInfoEventArgs : EventArgs { public TimeInfoEventArgs(int hour, int minute, int second) { this.hour = hour; this.minute = minute; this.second = second; } public readonly int hour; public readonly int minute; public readonly int second; } Đối tượng TimeInfoEventArgs sẽ có thông tin về giờ phút giâ y hiện thờ i. Nó định nghĩa mộ t bộ khở i tạo, ba phương thức, mộ t biến nguyên readonly. Ngo ài việc thêm vào mộ t sự kiện và delegate, lớp đố i tượng Clock có b a biến thành viên là : hour, minute, và second. Cuối cùng là một phương thức Run(): public void Run() { for(;;) { // ngừng 10 gi ây Thread.Sleep( 10 ); 327 Cơ Chế Ủy Quyền - Sự Kiện
  8. Ngôn Ngữ Lập Trình C# // l ấy thời gian hi ện hành System.DateTime dt = System.DateTime.Now; // nếu gi ây thay đổi cảnh báo cho subscriber if ( dt.Second != second) { // tạo TimeInfoEventArgs để truyền // cho subscriber TimeInfoEventArgs timeInformation = new TimeInfoEventArgs( dt.Hour, dt.Minute, dt.Second); // nếu có bất cứ lớp nào đăng ký thì cảnh báo if ( OnSecondChange != null) { OnSecondChange( this, timeInformation); } } // cập nhật trạng thái this.second = dt.Second; this.minute = dt.Minute; this.hour = dt.Hour; } } Phương thức Run tạo vò ng lặp vô hạn để kiểm tra đ ịnh k ỳ thời gian hệ thố ng. Nếu thời gian thay đ ổi từ đối tượng Clock hiện hành, thì nó sẽ cảnh báo cho tất cả các subscriber và sau đó cập nhật lại những trạng thái của nó. Bước đầu tiên là ngừng 10 giâ y: Thread.Sleep(10); Ở đ ây chú ng ta sử dụng phương thức tĩnh của lớp Thread từ System.Threading của .NET. Sử dụng phương thức Sleep() đ ể kéo dài kho ảng cách giữa hai lần thực hiện vòng lặp. Sau khi ngừ ng 10 mili giâ y, phương thức sẽ kiểm tra thời gian hiện hành: System.DateTime dt = System.DateTime.Now; Cứ khoảng 100 lần kiểm tra, thì một giâ y sẽ được gia tăng. Phương thứ c ghi nhận sự thay đổ i và cảnh b áo đến những subscriber củ a nó. Để làm đ ược điều này, đầu tiên phải tạo ra một đố i tượng TimeInfoEventArgs: if ( dt.Second != second) { // tạo TimeInfoEventArgs để truyền cho các subscriber TimeInfoEventArgs timeInformation = new TimeInfoEventArgs( dt.Hour, dt.Minute, dt.Second); 328 Cơ Chế Ủy Quyền - Sự Kiện
  9. Ngôn Ngữ Lập Trình C# } Và để cảnh báo cho những subscriber b ằng cách kích hoạt sự kiện OnSecondChange: // cảnh báo cho các subscriber if ( OnSecondChange != null) { OnSecondChange( this, timeInformation); } Nếu một sự kiện khô ng có bất cứ lớp subscriber nào đăng ký thì nó ước lượng giá trị là null. Phần kiểm tra bên trên xác đ ịnh giá trị của sự kiện có p hải là null hay khô ng, để đ ảm bảo rằng có tồn tại lớp đ ăng ký nhận sự kiện trước khi gọi sự kiện OnSecondChange. Chúng ta lưu ý rằng OnSecondChange lấ y hai tham số: nguồn phát ra sự kiện và đ ối tượng dẫn xu ất từ lớp EventArgs. Ở đây chúng ta có thể thấy rằng tham chiếu this củ a lớp clock được truyền bởi vì clock là nguồ n phát ra sự kiện. Tham số thứ hai là đ ối tượng TimeInfo- EventArgs được tạo ra ở dò ng lệnh b ên trên. Mộ t sự kiện được phát ra thì sẽ gọ i b ất cứ p hương thức nào đ ược đ ăng ký với lớp Clock thông qua delegate, chúng ta sẽ kiểm tra điều này sau. Mộ t khi mà sự kiện được phát ra, chú ng ta sẽ cập nhật lại trạng thái của lớp Class: this.second = dt.Second; this.minute = dt.Minute; this.hour = dt.Hour; Sau cù ng là chúng ta xây d ựng nhữ ng lớp có thể đăng ký vào các sự kiện nà y. Chú ng ta sẽ tạo hai lớp. Lớp đầu tiên là lớp DisplayClock. Chức năng chính của lớp này khô ng phải là lưu giữ thời gian mà chỉ để hiển thị t hời gian hiện hành ra màn hình console. Để đ ơn giản chú ng ta chỉ tạo hai phương thức cho lớp này. Phương thức thứ nhất có tên là Subscribe, phương thức chịu trách nhiệm đ ăng ký mộ t sự kiện OnSecondChange của lớp Clock. Phương thức thứ hai được tạo ra là trình xứ lý sự kiện TimeHasChanged: public class DisplayClock { public void Subscrible(Clock theClock) { theClock.OnSecondChange += new Clock.SecondChangeHandler(TimeHasChanged); } public void TimeHasChanged( object theClock, TimeInfoEventArgs ti) { Console.WriteLine(“Current Time: {0]:{1}:{2}”, ti.hour.ToString(), ti.minute.ToString(), ti.Second.ToString()); 329 Cơ Chế Ủy Quyền - Sự Kiện
  10. Ngôn Ngữ Lập Trình C# } } Khi phương thức đầu tiên Subscribe đ ược gọi, nó sẽ tạo ra mộ t delegate SecondChange- Handler mới, và truyền vào phương thức xử lý sự kiện TimeHasChanged của nó. Sau đó nó sẽ đăng ký d elegate vớ i sự kiện OnSecondChange củ a Clock. Lớp thứ hai mà chú ng ta tạo cũ ng sẽ đáp ứng sự kiện nà y, tên là LogCurrentTime. Thô ng thường lớp này ghi lại sự kiện vào trong tập tin, nhưng với mục đích minh họa của chú ng ta, nó sẽ ghi ra màn hình console: public class LogCurrentTime { public void Subscribe(Clock theClock) { theClock.OnSecondChange += new Clock.SecondChangeHandler(WriteLogEntry); } // thông thường phương thức này viết ra file // nhưng trong minh họa này chúng ta chỉ xuất // ra màn hì nh console mà thôi public void WriteLogEntry( object theClock, TimeInfoEventArgs ti) { Console.WriteLine(“Logging to file: {0}:{1}:{2}”, ti.hour.ToString(), ti.minute.ToString(), ti.second.ToString()); } } Ghi chú rằng những sự kiện được thêm vào b ằng cách sử dụ ng to án tử +=. Điều này cho phép những sự kiện mới được thêm vào sự kiện OnSecondChange củ a đố i tượng Clock mà khô ng có p há hủ y b ất cứ sự kiện nào đ ã được đ ăng ký . Khi LogCurrentTime đăng ký một sự kiện OnSecondChange, chúng ta khô ng muố n việc đăng ký nà y làm mất đi sự đ ăng ký của lớp DisplayClock trước đó. Tất cả phần còn lại cần thực hiện là tạo ra một lớp Clock, tạo mộ đố i tượng DisplayClock và bảo nó đ ăng ký sự kiện. Sau đó chúng ta tạo ra một đố i tượng LogCurrentTime và cũng đ ăng ký sự kiện tương tự. Cuối cù ng thì thực thi phương thức Run của Clock. Tất cả phần trên được trình bày trong ví ụ 11.4.  Ví dụ 11.4: làm việc với những sự kiện. ----------------------------------------------------------------------------- namespace Programming_CSharp 330 Cơ Chế Ủy Quyền - Sự Kiện
  11. Ngôn Ngữ Lập Trình C# { using System; using System.Threading; // l ớp lưu gi ữ thông tin về sự ki ện, trong trường hợp // này nó chỉ lưu gi ữ những thông tin có giá trị lớp clock public class TimeInfoEventArgs : EventArgs { public TimeInfoEventArgs(int hour, int minute, int second) { this.hour = hour; this.minute = minute; this.second = second; } public readonly int hour; public readonly int minute; public readonly int second; } // khai báo lớp Clock lớp này sẽ phát ra các sự ki ện public class Clock { // khai báo delegate mà các subscriber phải thực thi public delegate void SecondChangeHandler(object clock, TimeInfoEventArgs timeInformation); // sự ki ện mà chúng ta đưa ra public event SecondChangeHandler OnSecondChange; // thi ết l ập đồng hồ thực hiện, sẽ phát ra mỗi sự ki ện trong mỗi giây public void Run() { for(;;) { // ngừng 10 gi ây Thread.Sleep( 10 ); // l ấy thời gian hi ện hành System.DateTime dt = System.DateTime.Now; // nếu gi ây thay đổi cảnh báo cho subscriber if ( dt.Second != second) { // tạo TimeInfoEventArgs để truyền 331 Cơ Chế Ủy Quyền - Sự Kiện
  12. Ngôn Ngữ Lập Trình C# // cho subscriber TimeInfoEventArgs timeInformation = new TimeInfoEventArgs( dt.Hour, dt.Minute, dt.Second); // nếu có bất cứ lớp nào đăng ký thì cảnh báo if ( OnSecondChange != null) { OnSecondChange( this, timeInformation); } } // cập nhật trạng thái this.second = dt.Second; this.minute = dt.Minute; this.hour = dt.Hour; } } private int hour; private int minute; private int second; } // l ớp DisplayClock đăng ký sự ki ện của clock. // thực thi xử l ý sự ki ện bằng cách hi ện thời gian hi ện hành public class DisplayClock { public void Subscrible(Clock theClock) { theClock.OnSecondChange += new Clock.SecondChangeHandler(TimeHasChanged); } public void TimeHasChanged( object theClock, TimeInfoEventArgs ti) { Console.WriteLine(“Current Time: {0}:{1}:{2}”, ti.hour.ToString(), ti.minute.ToString(), ti.second.ToString()); } } // l ớp đăng ký sự ki ện thứ hai public class LogCurrentTime 332 Cơ Chế Ủy Quyền - Sự Kiện
  13. Ngôn Ngữ Lập Trình C# { public void Subscribe(Clock theClock) { theClock.OnSecondChange += new Clock.SecondChangeHandler(WriteLogEntry); } // thông thường phương thức này viết ra file // nhưng trong minh họa này chúng ta chỉ xuất // ra màn hì nh console mà thôi public void WriteLogEntry( object theClock, TimeInfoEventArgs ti) { Console.WriteLine(“Logging to file: {0}:{1}:{2}”, ti.hour.ToString(), ti.minute.ToString(), ti.second.ToString()); } } // l ớp Test minh họa sử dụng sự ki ện public class Test { public static void Main() { // tạo ra đối tượng clock Clock theClock = new Clock(); // tạo đối tượng DisplayClock đăng ký // sự ki ện và xử l ý sự ki ện DisplayClock dc = new DisplayClock(); dc.Subscribe(theClock); // tạo đối tượng LogCurrent và yêu cầu đăng // ký và xử l ý sự ki ện LogCurrentTime lct = new LogCurrentTime(); lct.Subscribe(theClock); // bắt đầu thực hiện vòng l ặp và phát sinh sự kiện // trong mỗi giây đồng hồ theClock.Run(); } } } 333 Cơ Chế Ủy Quyền - Sự Kiện
  14. Ngôn Ngữ Lập Trình C# -----------------------------------------------------------------------------  Kết quả thực hiện có thể như sau: Current Time: 11:54:20 Logging to file: 11:54:20 Current Time: 11:54:21 Logging to file: 11:54:21 Current Time: 11:54:22 Logging to file: 11:54:22 ----------------------------------------------------------------------------- Điều quan trọng chính củ a ví dụ minh họ a trên là việc tạo ra hai lớp đối tượng DisplayClock và lớp LogCurrentTime. Cả hai lớp này đều đăng ký một sự kiện Clock.OnSecondChange của lớp thứ ba là lớp Clock Lợi ích củ a cơ chế publish/subscribe là b ất cứ lớp nào cũ ng có thể được cảnh báo khi một sự kiện xuất hiện. Những lớp subscriber không cần biết cách mà Clock làm việc, và Clock cũng khô ng cần biết cách mà các lớp subscriber đ áp ứng với sự kiện mà nó đưa ra. Publisher và subscriber đ ược phân tách b ởi delegate, đây là một sự mong đ ợi cao, nó làm cho mã lệnh linh họat và mạnh mẽ hơn. Lớp Clock có thể thay đổ i cách dò thời gian mà khô ng làm ảnh hưởng đ ến b ất cứ lớp subscriber nào. Các lớp subscriber có thể thay đ ổi cách mà chú ng đáp ứng với sự thay đ ổi củ a thời gian mà khô ng tác độ ng với Clock. Cả hai lớp này hoạt động độc lập với nhau, và làm cho đo ạn chương trình d ễ duy trì hơn. Câu hỏi và trả lời Câu hỏi 1: Tóm tắt những nét cơ bản về u ỷ quyền? Trả lời 1: Ủy quyền là mộ t kiểu dữ liệu tham chiếu đ ươc dùng để đóng gói phương thứ c với các tham số và kiểu trả về xác đ ịnh. Ủy quyền cũng tương tự như con trỏ hà m trong ngôn ngữ C++. Tuy nhiên, trong ngôn ng ữ C# ủy quyền là kiểu dữ liệu hướng đối tượng, an toàn và bảo mật. Câu hỏi 2: Con trỏ hàm là gì ? Trả lời 2: Trong ngôn ngữ như C hay C++, có một chức năng gọi là con trỏ hà m. Mộ t con trỏ hà m được sử dụng để thiết lập cùng một nhiệm vụ như mộ t ủ y quyền. Tuy nhiên, con trỏ hàm trong C/C++ đ ơn giản không phải là mộ t đối tượng. Còn ủ y quyền trong C# là kiểu dữ liệu an toàn, được dùng để tham chiếu đến những phương thứ c, ủy quyền còn được sử dụng bởi những sự kiện. Câu hỏi thêm Câu hỏi 1: Có th ể sử dụng ủy quyền như mộ t thuộc tính hay không? Nếu có thể th ì sử dụng như thế nào? Cho biết ý ngh ĩa? Câu hỏi 2: Nếu có mộ t số hoạt động cần được thực hiện theo một thứ tự nhất định thì ta phải là m thế nào đ ể khi cần th ực hiện th ì gọi lần lượt thực hiện các hoạ t động đó? 334 Cơ Chế Ủy Quyền - Sự Kiện
  15. Ngôn Ngữ Lập Trình C# Câu hỏi 3: Công dụng của việc khai báo ủy quyền tĩnh? Khi nào th ì nên khai báo ủy quyền tĩnh khi nào th ì không nên? Câu hỏi 4: Một ủy quyền có thể gọi được nhiều hơn một phương th ức hay không? Chức năng nào trong C# hỗ trợ ủ y quyền nà y? Câu hỏi 5: Có phả i tấ t cả cá c ủy quyền đ ều là ủy quyền Multicast hay không? Điều kiện đ ể trở thành ủ y quyền Multicast? Câu hỏi 6: Cá c toán tử nào có thể dùng để thực hiện việc Multicast các ủ y quyền? Câu hỏi 7: S ự kiện là gì? Trong h ệ thống ứng dụng nào thì sự kiện được sử dụng nhiều? Câu hỏi 8: Những sự kiện trong C# được thực hiện thông qua cái gì? Câu hỏi 9: Hã y tóm lược quá trình tạo một sự kiện và giả i quyết sự kiện thông qua cơ chế ủ y quyền trong C#? Bài tập Bài tập 1: Viết chương trình minh họa sử dụng ủy quyền để th ực hiện việc sắp xếp cá c số nguyên trong mộ t mảng? Bài tập 2: Viết chương trình minh họa sử dụng ủy quyền để th ực hiện việc chuyển các ký tự thường thành ký tự hoa trong một chuỗ i? Bài tập 3: Viết chương trình kết hợp giữa delegate và sự kiện để minh họa một đồng hồ đ iện tử thể h iện giờ hiện hành trên màn hình console. 335 Cơ Chế Ủy Quyền - Sự Kiện
  16. Ngôn Ngữ Lập Trình C# Chương 12 CÁC LỚP CƠ SỞ .NET  Lớp đối tượng trong .NET Framework  Lớp Timer  Lớp về thư mục & hệ thống  Lớp Math  Lớp thao tác tập tin  Là m việc với tập tin dữ liệu  Câu hỏi & bà i tập Cho đến lúc này thì chúng ta đ ã tìm hiểu khá nhiều các lớp đối tượng mà ngô n ngữ C# cung cấp cho chúng ta. Và hiện tại chúng ta đã có thể viết được các chương trình C# thuần tú y dùng console làm giao diện kết xuất. Đố i với việc tìm hiểu b ất cứ ngô n ngữ lập trình nào thì việc viết các chương trình mà giao diện càng đơn giản thì càng tố t. Trong phần thứ hai (từ chương 14) củ a giáo trình chú ng ta sẽ tìm hiểu xây d ựng các ứng d ụng Windows thông qua Visual C#. Trong chương nà y chúng ta sẽ tìm hiểu các lớp cơ sở mà .NET cung cấp, các lớp này đơn giản giúp chú ng ta thực hiện tố t các thao tác nhập xu ất, các thao tác truy cập hệ thống, thực thi các phép toán họ c,... Lớp đối tượng trong .NET Framework NET Framework chứa số lượng nhiều nhữ ng kiểu dữ lớp, những kiểu liệt kê, nhữ ng cấu trú c, những giao diện và nhiều kiểu dữ liệu khác nữa. Thật vậy, có hàng ngàn số lượng các kiểu như trên. Những lớp nà y điều cho phép chú ng ta sử dụ ng trong chương trình C#. Chúng ta sẽ tìm hiểu mộ t vài kiểu dữ liệu thường sử dụ ng trong chương này. Các lớp đ ược trình bày thô ng qua các ví dụ minh họa đơn giản. Từ những ví dụ minh họ a cách sử d ụng các lớp cơ sở này chú ng ta có thể mở rộ ng đ ể tạo ra các chương trình phức tạp hơn. Common Language Specification (CLR) Những lớp bên trong Framework đ ược viết với ngô n ngữ đ ược xác nhận là chung nhất (CLR). CLR đ ã được đề cập vào phần đầu củ a sách khi chú ng ta thảo lu ận về MS.NET trong chương 1. 336 Các Lớp Cơ Sở .NET
  17. Ngôn Ngữ Lập Trình C# CLS là một tập hợp các lu ật hay các quy tắc mà tất cả các ngô n ngữ thực hiện bên trong .NET platform phải tu ân thủ theo. Tập hợp lu ật này cũng bao gồm kiểu d ữ liệu hệ thố ng chung, các kiểu d ữ liệu cơ b ản mà chúng ta được tìm hiểu trong chương 3 - Nền tảng ngôn ngữ C#. Bằng cách đưa vào các tập luật này, môi trường thực thi chung sẽ có thể thực thi mộ t chương trình mà không quan tâm đến cú pháp của ngô n ngữ đ ược sử dụ ng. Lợi ích theo sau của CLS là mã ngu ồn đ ược viết trong một ngôn ngữ có thể được gọ i sử dụ ng bởi một ngôn ngữ khác Bởi vì thông thường b ên trong Framework với CLS, chú ng có thể sử dụng khô ng chỉ ngôn ngữ C# mà còn bất cứ ngôn ngữ tương thích với CLS như là Visual Basic.NET và JScript.NET. Kiểu dữ liệu trong namespace Mã nguồ n b ên trong Framework được tổ chức b ên trong namespace. Có hàng trăm namespace b ên trong Framework đ ược sử dụng đ ể tổ chức hàng ngàn lớp đối tượng và các kiểu d ữ liệu khác. Mộ t vài namespace thì đ ược lưu trữ b ên trong namespace khác. Ví d ụ chúng ta đã sử dụng kiểu d ữ liệu DateTime đ ược chứa trong namespace System. Kiểu Random cũng đ ược chứa trong namespace System. Nhiều kiểu dữ liệu phục vụ cho thao tác nhập xu ất cũng đ ược lưu trữ trong mộ t namespace chức trong namespace System là namespace System.IO. Nhiều kiểu dữ liệu thường dù ng để làm việc với dữ liệu XML thì đ ược đ ặt bên trong namespace System.XML. Chú ng ta có thể tìm hiểu các namespace này trong các tài liệu trực tuyến của Microsoft như MSDN Online chẳng hạn. Tiêu chuẩn ECMA Không phải tất cả kiểu dữ liệu bên trong namespace thì cần thiết phải tương thích với tất cả những ngô n ngữ khác. Hơn thế nữa, những công cụ p hát triển được tạo bởi những cô ng ty khác cho ngôn ngữ C# có thể khô ng bao hàm phải tương thích với mã ngu ồn thông thường. Khi ngôn ngữ C# đ ược hình thành. Microsoft xác nhận đ ưa ra một số lượng lớn các kiểu dữ liệu cho cù ng một bảng tiêu chu ẩn cho C# để chu ẩn hóa. Bằng cách xác nhận những kiểu d ữ liệu theo một tiêu chu ẩn, điều này xem như việc mở cánh cửa cho nhữ ng nhà phát triển khác tạo ra các cô ng cụ và trình biên dịch C# cù ng sử dụng những namespace và kiểu dữ liệu. Khi đó nhữ ng mã nguồn b ên trong những cô ng cụ củ a Microsoft tương thích với bất cứ cô ng cụ của các công ty khác. Nhữ ng lớp đối tượng được chu ẩn hóa thì đ ược đ ịnh vị b ên trong namespace System. Những namespace khác chứa nhữ ng lớp khô ng được chu ẩn hóa. Nếu mộ t lớp không phải là mộ t phần của tiêu chu ẩn, nó sẽ khô ng được hỗ trợ trong tất cả hệ đ iều hành và môi trường thực thi mà chú ng được viết để hỗ trợ C#. Ví dụ, Microsoft thêm vào mộ t vài namespace với SDK củ a nó như Microsoft.VisualBasic, Microsoft.CSharp, Microsoft.Jscript và Microsoft.Win32. Những namespace này khô ng phải là một phần của tiêu chuẩn ECMA. Do đó chúng có thể không có giá trị trong tất cả môi trường phát triển. 337 Các Lớp Cơ Sở .NET
  18. Ngôn Ngữ Lập Trình C# Tìm hiểu những lớp Framework Như chúng ta đ ã biết là có hàng ngàn những lớp và nhữ ng kiểu d ữ liệu khác bên trong thư viện cơ sở. Có thể sẽ tố n vài cuố n sách có kích thước như giáo trình nà y để nói toàn bộ về chú ng. Trước khi chúng ta tìm hiểu những lớp cơ bản, b ạn có thể xem tổng quan tài liệu trực tuyến để b iết thêm các lớp cơ cở. Tất cả các lớp và nhữ ng kiểu d ữ liệu khác được trình b ày trong chương này đ iều là một phần của tiêu chu ẩn đ ược xác nhận bởi ECMA. Lưu ý: Không những chúng ta có thể sử dụng những kiểu dữ liệu bên trong những lớp thư viện mà chúng ta còn có thể mở rộng những kiểu dữ liệu này. Lớp Timer Chúng ta b ắt đầu với ví dụ đ ầu tiên 12.1. Ví dụ minh họ a nà y hết sức đ ơn giản và được thiết kế khô ng đ ược tốt.  Ví dụ 12.1: Hiển thị thời gian. ----------------------------------------------------------------------------- // Timer01.cs: Hi ển thị ngày và thời gian // nhấn Ctrl+C để thoát namespace Programming_CSharp { using System; public class Tester { public static void Main() { while (true) { Console.WriteLine(“\n {0}”, DateTime.Now); } } } } -----------------------------------------------------------------------------  Kết quả: 12/24/2001 3:21:20 PM ....... ....... ----------------------------------------------------------------------------- Như chú ng ta có thể thấy, kết qu ả chương trình được thực thi vào lúc 3:21 vào ngà y 24 tháng 12. Danh sách này thể hiện một đồng hồ xu ất hiện ở dò ng lệnh, và chúng dường như là được 338 Các Lớp Cơ Sở .NET
  19. Ngôn Ngữ Lập Trình C# cập nhật trong mỗi giâ y đồ ng hồ. Thật vậy, nó thông thườ ng được cập nhật nhiều hơn mộ t lần, do đó chúng ta lưu ý là giâ y đồ ng hồ thay đ ổi chỉ khi giá trị xu ất hiện thật sự khác nhau. Chương trình sẽ chạ y mãi đ ến khi nào ta nhấn thoát b ằng Ctrl + C. Trong chương trình ta sử dụng kiểu dữ liệu DateTime, đây là một cấu trúc đ ược chứa trong namespace System bên trong thư viện cơ sở. Cấu trúc này có một thuộ c tính tĩnh là Now trả về thời gian hiện hành. Có nhiều d ữ liệu thành viên và những phương thức được thêm vào trong cấu trú c DateTime. Chú ng ta có thể tìm hiểu thêm về DateTime trong thư viện trực tuyến về các lớp cơ sở củ a .NET Framework. Cách tố t nhất đ ể hiện thị ngày giờ trên màn hình là sử dụ ng Timer. Một Timer cho phép mộ t xử lý (hình thức của một delegate) được gọi tại một thời gian xác đ ịnh hay sau một chu kỳ nào đó trô i qua. Framework chứa một lớp Timer bên trong namespace System.Timers. Lớp này được sử dụ ng trong ví dụ 12.2 theo sau:  Ví dụ 12.2: Sử dụng Timer. ----------------------------------------------------------------------------- // Timer02.cs: hi ểu thị ngày gi ờ sử dụng Timer // nhấn Ctrl+C hay ‘q’ và Enter để thoát namespace Programming_CSharp { using System; using System.Timers; public class Tester { public static void Main() { Timer myTimer = new Timer(); // khai báo hàm xử l ý myTimer.Elapsed += new ElapsedEventHandler( DisplayTimeEvent); // khoảng thời gian delay myTimer.Interval = 1000; myTimer.Start(); // thực hi ện vòng l ặp để chờ thoát while ( Console.Read() != ‘q’) { ; // không l àm gì hết! } } public static void DisplayTimeEvent( object source, ElapsedEventArgs t) { 339 Các Lớp Cơ Sở .NET
  20. Ngôn Ngữ Lập Trình C# Console.Write(“\n{0}”, DateTime.Now); } } } -----------------------------------------------------------------------------  Kết quả: 12/24/2001 3:45:20 PM ...... ...... ----------------------------------------------------------------------------- Kết qu ả thực hiện cũng giố ng như ví d ụ trước. Tuy nhiên, chương trình nà y thự c hiện tốt hơn nhiều so với chương trình ban đ ầu. Thay vì cập nhật không ngừ ng ngà y giờ được hiển thị, chương trình nà y chỉ cập nhật sau khoảng 1 giây. Chúng ta hã y xem kỹ cách mà Timer làm việc. Một đố i tượng Timer mới được tạo ra, thuộc tính Interval đ ược thiết lập. Tiếp theo phương thức sẽ được thực hiện sau kho ảng thời gian interval đ ược gắn với Timer. Trong trường hợp nà y là phương thức DisplayTimeEvent sẽ đ ựơc thực thi, phương thức được đ ịnh nghĩa ở b ên d ưới. Khi Timer thực hiện phương thức Start thì nó sẽ bắt đ ầu tính interval. Mộ t thuộc tính thành viên khác củ a Timer là AutoReset mà chú ng ta cũng cần biết là: nếu chúng ta thay đổi giá trị mặc đ ịnh của nó từ true sang false, thì sự kiện Timer chỉ thực hiện duy nhất mộ t lần. Khi AutoReset có giá trị true hay ta thiết lập giá trị true thì Timer sẽ kích ho ạt sự kiện và thực thi phương thức mỗi mộ t thời gian được đưa ra (interval). Trong chương trình nà y vẫn chứa một vò ng lặp thực hiện đến khi nào ngườ i dù ng nhấn ký tự ‘q’ và Enter. Nếu khô ng chương trình thực hiện tiếp tục vòng lặp. Không có gì thực hiện trong vòng lặp này, nếu muốn chú ng ta có thể thêm vào trong vòng lặp nhữ ng xứ lý khác. Chúng ta cũ ng không cần thiết phải gọ i phương thức DisplayTimeEvent trong vò ng lặp bởi vì nó sẽ được gọi tự động vào khoảng thời gian xác định interval. Timer trong chương trình nà y dù ng để thể hiện ngày giờ trên màn hình. Timer và những sự kiện của Timer cũng có thể được sử dụng cho nhiều chương trình khác. Như chúng ta có thể tạo Timer để tắt một chương trình khác vào một thời đ iểm đ ưa ra. Chúng ta cũ ng có thể tạo chương trình backup thường xuyên đ ể sao chép những dữ liệu quan trọ ng theo một định kỳ thời gian nào đó. Hay chúng ta cũng có thể tạo một chương trình tự động log off một người sử dụng hay kết thú c một chương trình sau mộ t kho ảng thờ i gian mà không có bất cứ ho ạt độ ng nào xả y ra. Nói chung là có rất nhiều cách sử dụng Timer này, và lớp Timer này rất hữa ích. Lớp về thư mục và hệ thống Đô i khi chúng ta cần biết thô ng tin hệ thố ng của máy mà chương trình đ ang thực hiện, điều này khô ng khó khăn gì, .NET hỗ trợ một số lớp cơ bản để thực hiện việc này. Trong ví 340 Các Lớp Cơ Sở .NET
ADSENSE

CÓ THỂ BẠN MUỐN DOWNLOAD

 

Đồng bộ tài khoản
2=>2