Tải bản đầy đủ (.pdf) (12 trang)

Tài liệu THỰC THI GIAO DIỆN phần 3 pdf

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

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 ICompressibl
e
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
suppo
rted”

Đ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 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”);

}




}
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 ICompressibl
e
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...

.....




public void Read()

{...}

public void Write( object o)

{...}

//....

}



Thực thi phủ quyết giao diện

Khi thực thi một lớp chúng ta có thể tự do đánh dấu bất kỳ hay tất cả các
phương thức thực thi giao diện như là một phương thức ảo. Ví dụ, lớp
Document thực thi giao diện IStorable và có thể đánh dấu các phương thức Read() và
Write() như là phương thức ảo. Lớp Document có thể đọc và viết nội dung của nó
vào một kiểu dữ li
ệu File. Những người phát triển sau có thể dẫn xuất một kiểu dữ
liệu mới từ lớp Document, có thể là lớp Note hay lớp EmailMessage, và những người
này mong muốn lớp Note đọc và viết vào cơ sở dữ liệu hơn là vào một tập tin.
Ví dụ 8.4 mở rộng từ ví dụ 8.3 và minh họa việc phủ quyết một thực thi giao diện.
Phương thức Read() được đánh dấu như phươ
ng thức ảo và thực thi bởi
Document.Read() và cuối cùng là được phủ quyết trong kiểu dữ liệu Note được dẫn
xuất từ Document.
Ví dụ 8.4: Phủ quyết thực thi giao diện.
-----------------------------------------------------------------------------

using System;

interface IStorable

{


void Read();

void Write();

}



// lớp Document đơn giản thực thi giao diện
IStorable public class Document : IStorable
{


// bộ khởi dựng

public Document( string s)

{


Console.WriteLine(“Creating document with: {0}”, s);

}


// đánh dấu phương thức Read ảo
public virtual void Read()

×