Trong ví dụ 8.6, giao diện IStorable có một phương thức Read() và môt thuộc tính là Status. Giao diện này được thực thi bởi một cấu trúc tên là myStruct:

public struct myStruct : IStorable

Đoạn mã nguồn thú vị bên trong Tester. Chúng ta bắt đầu bằng việc tạo một thể hiện của cấu trúc và khởi tạo thuộc tính là –1, sau đó giá trị của status được in ra:0

myStruct theStruct = new myStruct();

theStruct.Status = -1; // khởi tạo

Console.WriteLine(“theStruct.Status: {0}”, theStruct.status);

Kết quả là giá trị của status được thiết lập:

theStruct.Status = -1;

Kế tiếp chúng ta truy cập thuộc tính để thay đổi status, một lần nữa thông qua đối tượng giá trị:

// thay đổi giá trị

theStruct.Status = 2;

Console.WriteLine(“Changed object”);

Console.WriteLine(“theStruct.Status: {0}”, theStruct.Status);

kết quả chỉ ra sự thay đổi:

Changed object

theStruct.Status: 2

Tại điểm này, chúng ta tạo ra một tham chiếu đến giao diện IStorable, một đối tượng giá

trị theStruct được boxing ngầm và gán lại cho tham chiếu giao diện. Sau đó chúng ta dùng giao diện để thay đổi giá trị của status bằng 4:

// gán cho một giao diện

// boxing ngầm định

IStorable isTemp = (IStorable) theStruct;

// thiết lập giá trị thông qua tham chiếu giao diện

isTemp.Status = 4;

Console.WriteLine(“Changed interface”);

Console.WriteLine(“theStruct.Status: {0}, isTemp:

{1}”,

theStruct.Status, isTemp.Status);

như chúng ta đã thấy kết quả thực hiện có một điểm khác biệt:

Changed interface

theStruct.Status: 2, isTemp: 4

Điều xảy ra là: đối tượng được giao diện tham chiếu đến thay đổi giá trị status bằng 4, nhưng đối tượng giá trị cấu trúc không thay đổi.Thậm chí có nhiều thú vị hơn khi chúng ta truy cập phương thức thông qua bản thân đối tượng:

// than đổi giá trị lần nữa

theStruct.Status = 6;

Console.WriteLine(“Changed

object”);

Console.WriteLine(“theStruct.Status: {0}, isTemp:

{1}”, theStruct.Status, isTemp.Status);

kết quả đối tượng giá trị thay đổi nhưng đối tượng được boxing và được giao diện tham chịếu không thay đổi:

Changed object

theStruct.Status: 6, isTemp: 4

Ta thử xem đoạn mã IL để hiểu tham về cách thực hiện trên:

Ví dụ 8.7: MSIL phát sinh từ ví dụ 8.6.

-----------------------------------------------------------------------------

method private hidebysig static void Main() il managed {

.entrypoint

// Code size 206 (0xce)

.maxstack 4

.local ([0] value class myStruct theStruct,

[1] class IStorable isTemp, [2] int32 V_2)

instance void myStruct::set_status(int32) “theStruct.Status: {0}” theStruct instance int32 myStruct::get_status()

IL_0000: IL_0002: IL_0008: IL_000a: IL_000b: IL_0010: IL_0015: IL_0017: IL_001c: IL_001d: IL_001f: IL_0024: ldloca.s theStruct iniobj myStruct ldloca.s theStruct ldc.i4.ml call ldstr ldloca.s call stloc.2 ldloca.s V_2 box call [mscorlib]System.Int32 void [mscorlib] System.Console::WriteLine

(class System.String, class System.Object)

IL_0029: ldloca.s theStruct

IL _0 02 IL_002b: ldc.i4.2

c: call instance void myStruct::set_status(int32)

IL_0031: IL_0036: ldstr call “Changed object” void [mscorlib]System.Console::WriteLine

(class System.String) ldstr ldloca.s call stloc.2 ldloca.s V_2 box call

“theStruct.Status: {0}” theStruct instance int32 myStruct::get_status()

IL_003b: IL_0040: IL_0042: IL_0047: IL_0048: IL_004a: IL_004f: [mscorlib]System.Int32 void [mscorlib]System.Console::WriteLine

(class System.String, class System.Object) ldloca.s box stloc.1 ldloc.1 ldc.i4.4 callvirt ldstr call

theStruct myStruct

IL_0054: IL_0056: IL_005b: IL_005c: IL_005d: IL_005e: IL_0063: IL_0068: instance void IStorable::set_status(int32) “Changed interface” void [mscorlib]System.Console::WriteLine

“theStruct.Status: {0}, isTemp: {1}” theStruct instance int32 mySystem::get_status()

(class System.String) ldstr ldloca.s call stloc.2 ldloca.s V_2 box ldloc.1

[mscorlib]System.Int32

instance int32 IStorable::get_status()

IL_0082: IL_0087: IL_0088: IL_008a: IL_008f:

callvirt stloc.2 ldloca.s V_2 box call

IL_006d: IL_0072: IL_0074: IL_0079: IL_007a: IL_007c: IL_0081:

[mscorlib]System.Int32 void [mscorlib]System.Console::WriteLine

(class System.String, class System.Object, class System.Object)

IL_0094: ldloca.s theStruct

IL_0096: ldc.i4.6

IL_0097: call instance void myStruct::set_status(int32)

IL_009c: ldstr “Changed object” I L _ 0 0 a 1

void call : [mscorlib]System.Console::WriteLine

“theStruct.Status: {0}, isTemp: {1}” theStruct instance int32 myStruct::get_status()

[mscorlib]System.Int32

(class System.String) ldstr ldloca.s call stloc.2 ldloca.s V_2 box ldloc.1

IL_00a6: IL_00ab: IL_00ad: IL_00b2: IL_00b3: IL_00b5: IL_00ba:

instance int32 IStorable::get_status()

IL_00bb: IL_00c0: IL_00c1: IL_00c3: IL_00c8:

callvirt stloc.2 ldloca.s V_2 box call

[mscorlib]System.Int32 void [mscorlib]System.Console::WriteLine

(class System.String, class System.Object, class System.Object)

IL_00cd:

ret

} // end fo method Tester::Main

----------------------------------------------------------------------------- Trong dòng lệnh IL_00b, giá trị của status được thiết lập thông qua việc gọi đối tượng giá trị. Tiếp theo chúng ta thấy lệnh gọi thứ hai ở dòng IL_0017. Lưu ý rằng việc gọi WriteLine() dẫn đến việc boxing một giá trị nguyên để phương thức GetString của lớp object được gọi.

Điều muốn nhấn mạnh là ở dòng lệnh IL_0056 khi một cấu trúc myStruct đã được boxing. Việc boxing này tạo ra một kiểu dữ lịêu tham chiếu cho tham chiếu giao diện. Và điều quan trọng là ở dòng IL_005e lúc này IStorable::set_status được gọi chứ không phải là myStruct::setStatus.

Điều quan trọng muốn trình bày ở đây là khi chúng ta thực thi một giao diện với một kiểu giá trị, phải chắc chắn rằng truy cập các thành viên của giao diện thông qua đối tượng hơn là thông qua một tham chiếu giao diện.