1. Trang chủ
  2. » Giáo Dục - Đào Tạo

Giáo trình hướng dẫn truy cập phương thức gán đối tượng cho một giao diện đối lập trừu tượng p4 ppt

5 194 0

Đ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 5
Dung lượng 868,07 KB

Nội dung

Ngôn Ngữ Lập Trình C# void Compress(); void Decompress(); } Nếu đưa ra một kiểu Document, và ta cũng không biết là lớp này có hỗ trợ giao diện IStorable hay ICompressible hoặc cả hai. Ta có thể có đoạn chương trình sau: Document doc = new Document(“Test Document”); IStorable isDoc = (IStorable) doc; isDoc.Read(); ICompressible icDoc = (ICompressible) doc; icDoc.Compress(); Nếu Document chỉ thực thi giao diện IStorable: public class Document : IStorable phép gán cho ICompressible vẫn được biên dịch bởi vì ICompressible là một giao diện hợp lệ. Tuy nhiên, do phép gán không hợp lệ nên khi chương trình chạy thì sẽ tạo ra một ngoại lệ (exception): A exception of type System.InvalidCastException was thrown. Phần ngoại lệ sẽ được trình bày trong Chương 11. Toán tử is Chúng ta muốn kiểm tra một đối tượng xem nó có hỗ trợ giao diện, để sau đó thực hiện các phương thức tương ứng. Trong ngôn ngữ C# có hai cách để thực hiện điều này. Phương pháp đầu tiên là sử dụng toán tử is. Cú pháp của toán tử is là: <biểu thức> is <kiểu dữ liệu> Toán tử is trả về giá trị true nếu biểu thức thường là kiểu tham chiếu có thể được gán an toàn đến kiểu dữ liệu cần kiểm tra mà không phát sinh ra bất cứ ngoại lệ nào. Ví dụ 8.3 minh họa việc sử dụng toán tử is để kiểm tra Document có thực thi giao diện IStorable hay ICompressible.  Ví dụ 8.3: Sử dụng toán tử is. using System; interface IStorable { void Read(); void Write(object obj); int Status { get; set; } } // giao diện mới Thực Thi Giao Diện 188 Ngôn Ngữ Lập Trình C# interface ICompressible { void Compress(); void Decompress(); } // Document thực thi IStorable public class Document : IStorable { public Document( string s) { Console.WriteLine(“Creating document with: {0}”, s); } // IStorable public void Read() { Console.WriteLine(“Implementing the Read Method for IStorable”); } // IStorable.WriteLine() public void Write( object o) { Console.WriteLine(“Implementing the Write Method for IStorable”); } // IStorable.Status public int Status { get { return status; } set { status = value; } } // bien thanh vien luu gia tri cua thuoc tinh Status private int status = 0; } public class Tester Thực Thi Giao Diện 189 Ngôn Ngữ Lập Trình C# { static void Main() { Document doc = new Document(“Test Document”); // chỉ gán khi an toàn if ( doc is IStorable ) { IStorable isDoc = (IStorable) doc; isDoc.Read(); } // việc kiểm tra này sẽ sai if ( doc is ICompressible ) { ICompressible icDoc = (ICompressible) doc; icDoc.Compress(); } } } Trong ví dụ 8.3, hàm Main() lúc này sẽ thực hiện việc gán với interface khi được kiểm tra hợp lệ. Việc kiểm tra này được thực hiện bởi câu lệnh if: if ( doc is IStorable ) Biểu thức điều kiện sẽ trả về giá trị true và phép gán sẽ được thực hiện khi đối tượng có thực thi giao diện bên phải của toán tử is. Tuy nhiên, việc sử dụng toán tử is đưa ra một việc không có hiệu quả. Để hiểu được điều này, chúng ta xem đoạn chương trình được biên dịch ra mã IL. Ở đây sẽ có một ngoại lệ nhỏ, các dòng bên dưới là sử dụng hệ thập lục phân: IL_0023: isinst ICompressible IL_0028: brfalse.s IL_0039 IL_002a: ldloc.0 IL_002b: castclass ICompressible IL_0030: stloc.2 IL_0031: ldloc.2 IL_0032: callvirt instance void ICompressible::Compress() IL_0037: br.s IL_0043 IL_0039: ldstr “Compressible not supported” Điều quan trọng xảy ra là khi phép kiểm tra ICompressible ở dòng 23. Từ khóa isinst là mã MSIL tương ứng với toán tử is. Nếu việc kiểm tra đối tượng (doc) đúng kiểu của kiểu bên Thực Thi Giao Diện 190 Ngôn Ngữ Lập Trình C# phải. Thì chương trình sẽ chuyển đến dòng lệnh 2b để thực hiện tiếp và castclass được gọi. Điều không may là castcall cũng kiểm tra kiểu của đối tượng. Do đó việc kiểm tra sẽ được thực hiện hai lần. Giải pháp hiệu quả hơn là việc sử dụng toán tử as. Toán tử as Toán tử as kết hợp toán tử is và phép gán bằng cách đầu tiên kiểm tra hợp lệ phép gán (kiểm tra toán tử is trả về true) rồi sau đó phép gán được thực hiện. Nếu phép gán không hợp lệ (khi phép gán trả ề giá trị false), thì toán tử as trả về giá trị null. Ghi chú: Từ khóa null thể hiện một tham chiếu không tham chiếu đến đâu cả (null reference). Đối tượng có giá trị null tức là không tham chiếu đến bất kỳ đối tượng nào. Sử dụng toán tử as để loại bỏ việc thực hiện các xử lý ngoại lệ. Đồng thời cũng né tránh việc thực hiện kiểm tra dư thừa hai lần. Do vậy, việc sử dụng tối ưu của phép gán cho giao diện là sử dụng as. Cú pháp sử dụng toán tử as như sau: <biểu thức> as <kiểu dữ liệu> Đoạn chương trình sau thay thế việc sử dụng toán tử is bằng toán tử as và sau đó thực hiện việc kiểm tra xem giao diện được gán có null hay không: static void Main() { Document doc = new Document(“Test Document”); IStorable isDoc = doc as IStorable; if ( isDoc != null ) { isDoc.Read(); } else { Console.WriteLine(“IStorable not supported”); } ICompressible icDoc = doc as ICompressible; if ( icDoc != null) { icDoc.Compress(); } else { Console.WriteLine(“Compressible not supported”); } Thực Thi Giao Diện 191 Ngôn Ngữ Lập Trình C# } Ta có thể so sánh đoạn mã IL sau với đoạn mã IL sử dụng toán tử is trước sẽ thấy đoạn mã sau có nhiều hiệu quả hơn: IL_0023: isinst ICompressible IL_0028: stloc.2 IL_0029: ldloc.2 IL_002a: brfalse.s IL_0034 IL_002c: ldloc.2 IL_002d: callvirt instance void ICompressible::Compress() Ghi chú: Nếu mục đích của chúng ta là kiểm tra một đối tượng có hỗ trợ một giao diện và sau đó là thực hiện việc gán cho một giao diện, thì cách tốt nhất là sử dụng toán tử as là hiệu quả nhất. Tuy nhiên, nếu chúng ta chỉ muốn kiểm tra kiểu dữ liệu và không thực hiện phép gán ngay lúc đó. Có lẽ chúng ta chỉ muốn thực hiện việc kiểm tra nhưng không thực hiện việc gán, đơn giản là chúng ta muốn thêm nó vào danh sách nếu chúng thực sự là một giao diện. Trong trường hợp này, sử dụng toán tử is là cách lựa chọn tốt nhất. Giao diện đối lập với lớp trừu tượng Giao diện rất giống như các lớp trừu tượng. Thật vậy, chúng ta có thể thay thế khai báo của IStorable trở thành một lớp trừu tượng: abstract class Storable { abstract public void Read(); abstract public void Write(); } Bây giờ lớp Document có thể thừa kế từ lớp trừu tượng IStorable, và cũng không có gì khác nhiều so với việc sử dụng giao diện. Tuy nhiên, giả sử chúng ta mua một lớp List từ một hãng thứ ba và chúng ta muốn kết hợp với lớp có sẵn như Storable. Trong ngôn ngữ C++ chúng ta có thể tạo ra một lớp StorableList kế thừa từ List và cả Storable. Nhưng trong ngôn ngữ C# chúng ta không thể làm được, chúng ta không thể kế thừa từ lớp trừu tượng Storable và từ lớp List bởi vì trong C# không cho phép thực hiện đa kế thừa từ những lớp. Tuy nhiên, ngôn ngữ C# cho phép chúng ta thực thi bất cứ những giao diện nào và dẫn xuất từ một lớp cơ sở. Do đó, bằng cách làm cho Storable là một giao diện, chúng ta có thể kế thừa từ lớp List và cũng từ IStorable. Ta có thể tạo lớp StorableList như sau: public class StorableList : List, IStorable { // phương thức List Thực Thi Giao Diện 192 . chọn tốt nhất. Giao diện đối lập với lớp trừu tượng Giao diện rất giống như các lớp trừu tượng. Thật vậy, chúng ta có thể thay thế khai báo của IStorable trở thành một lớp trừu tượng: abstract. ICompressible::Compress() Ghi chú: Nếu mục đích của chúng ta là kiểm tra một đối tượng có hỗ trợ một giao diện và sau đó là thực hiện việc gán cho một giao diện, thì cách tốt nhất là sử dụng toán tử as là hiệu quả. chỉ thực thi giao diện IStorable: public class Document : IStorable phép gán cho ICompressible vẫn được biên dịch bởi vì ICompressible là một giao diện hợp lệ. Tuy nhiên, do phép gán không hợp

Ngày đăng: 26/07/2014, 04:21

TỪ KHÓA LIÊN QUAN

TÀI LIỆU CÙNG NGƯỜI DÙNG

TÀI LIỆU LIÊN QUAN