Tài liệu C# và kiến trúc .NET part 5 - Pdf 98


Tìm hiểu về Intermediate Language
Như chúng ta đã biết, Intermediate Language hoạt động như là bản chất của .NET
Framework. Là lập trình viên C#, chúng ta nên biết rằng mã C# sẽ luôn được dịch sang
Intermediate Language trước khi nó được thực thi (thật vậy, trình biên dịch C# chỉ dịch
sang mã có quản). Chúng ta hãy cùng khám phá các tính năng chính của IL, bất kì ngôn
ngữ nào hướng .NET cũng sẽ hỗ trợ các đặc tính chính của IL.
Sau đây là những đặc tính chính của Intermediate Language:
• Hướng đối tượng và dùng interfaces
• Sự tách biệt giữa kiểu giá trị và kiểu tham chiếu
• Định kiểu mạnh
• Quản lỗi thông qua các ngoại lệ
• Sự dụng các thuộc tính
Bây giờ chúng ta sẽ cùng khám phá các đặc tính trên.
Hỗ trợ hướng đối tượng và dùng giao diện
Ngôn ngữ độc lập nền của .NET có một vài giới hạn riêng. Cụ thể trong lúc thực thi IL
chắc chắn sẽ thực thi một cách thức lập trình riêng, và các ngôn ngữ khác phải chú ý đến
việc tương thích với cách thức lập trình này. IL đã được Microsoft phát triển như là một
ngôn ngữ hướng đối tượ
ng cổ điển hỗ trợ đầy đủ thừa kế đơn giữa các lớp.
Bên cạnh lập trình hướng đối tượng đơn, Intermediate Language còn nêu ra ý tưởng về
interfaces (giao diện), cái đã được tích hợp trong Windows với giao diện COM. .NET nó
không giống như giao diện COM; chúng không cần phải hỗ trợ bất kì một kiến trúc COM
nào (ví dụ, chúng không xuất phát từ IUnknown, và chúng cũng không liên quan gì đến
các GUID). Tuy nhiên chúng có thể dùng chung các giao diện COM.
Hướng đối tượng và thực thi chéo ngôn ng

Bây chúng ta sẽ tìm hiểu về hoạt động của .NET nghĩa là hoạt động biên dịch sang mã
Intermediate Language, điều đó nói lên rằng bạn cần phải lập trình theo cách thức hướng
đối tượng truyền thống. Không những thế chúng còn cung cấp cho chúng ta khả năng
chuyển giao ngôn ngữ. Sau cùng, C++ và Java cả hai đều dùng những biến thể của hướng

Như bất kì ngôn ngữ lập trình nào, IL cung cấp một s
ố tiền định nghĩa về các kiểu dữ liệu
nguyên thủy. Một đặc trưng của Intermediate Language là phân biệt rạch ròi giữa kiểu dữ
liệu giá trị và kiểu dữ liệu tham chiếu. Kiểu giá trị là các biến được dùng để lưu trực tiếp
giá trị, trong khi đó kiểu tham chiếu là các biến chứa địa chỉ của dữ liệu.
Trong C++, kiểu tham chiếu có thể coi như là m
ột con trỏ, trong khi đó ở Visual Basic,
kiểu tham chiếu có thể coi là các đối tượng, trong VB 6 luôn truy cập thông qua tham
chiếu. Intermediate Language cũng chỉ rõ về cách thức lưu trữ dữ liệu: ví như một kiểu
tham chiếu luôn được lưu trong vùng managed heap của bộ nhớ, trong khi đó kiểu giá trị
lại được lưu trong stack (tuy nhiên nếu kiểu dữ liệu được khai báo là một trường của kiểu
tham chiếu, chúng vẫn được l
ưu ở heap). Chúng ta sẽ bàn về stack và heap trong chương
3.
Định kiểu mạnh
Một điểm mạnh trong IL là định kiểu mạnh. Nghĩa là tất cả các biếu đều được đánh dấu
rõ ràng và chuyên biệt về kiểu dữ liệu (IL không còn hỗ trợ kiễu Variant cho Visual
Basic và ngôn ngữ kịch bản). Cụ thể là IL không cho phép các hoạt động trả về các kiểu
dữ liệu không rõ ràng.
Trong trường hợp là người phát triển VB có lẽ bạn sẽ rất lo lắng về kiểu, bởi vì khi dùng
kiể
u dữ liệu Variant VB tự động ép kiểu giúp bạn. Còn là người phát triển C++, có lẽ bạn
sẽ dùng các casting pointer giữa các kiểu. Lập trình theo cách này có thể là một lập trình
mạnh, tuy nhiên nó phá vỡ tính an toàn kiểu. Từ bây giờ, nó chỉ còn hỗ trợ trong những
trường hợp đặc biệt trong một số ngôn ngữ có khả năng biên dịch sang mã có quản. Thật
vậy, các con trỏ (không phải là tham chiếu) chỉ còn cho phép trong các khối mã đặc biệt
trong C#, trong VB không có (mặc dù nó cho phép trong C++). Nế
u dùng con trỏ trong
mã nguồn nó sẽ không chuyển thành mã có quản và sẽ không được kiểm tra bởi CLR.
Bạn cũng nên biết rằng trong một số ngôn ngữ biết .NET, chẳng hạn như VB.NET, vẫn

kiểu Int32 trong IL. Nó phải được biên dịch thành mã IL. Bởi vì trình biên dịch C# cũng
biết ki
ểu dữ liệu này nên không có vấn đề gì cả. Ở cấp mã nguồn, C# gọi Int32 là int, vì
vậy khi biên dịch hàm VB.NET đơn giản trả về một kiểu int.
CTS không chỉ đơn thuần là các kiểu dữ liệu đơn giản, doesn't merely specify primitive
data types, mà nó còn cho phép chúng ta tự định nghĩa kiểu của riêng mình.
Các kiểu được trình bày trong bảng dưới đây:
Kiểu Giải thích
Type Kiểu cơ bản dùng để mô tả các kiểu khác
Value Type Kiểu cơ bản dùng để mô tả các kiểu giá trị.
Reference Types Kiểu cơ bản dùng để môt tả các kiểu tham trị.
Built-in Value Types Bao gồm các kiểu giá trị nguyên thủy chuẩn, như các kiểu
số, kiểu luận lí, kiểu kí tự.
Enumerations Bộ các giá trị liệt kêSets of enumerated values.
User-defined Value Types Kiểu được định nghĩa trong mã nguồn như là một kiểu giá
trị. Trong C# nó có là struct.
Interface Types Các giao diện.
Pointer Types Các con trỏ.
Self-describing Types Kiểu dữ liệu có quản.
Arrays Các kiểu chứa mảng các đối tượng.
Class Types Các kiểu tự mô tả nhưng không phải là mảng.
Delegates Kiểu được thiết kế để tham chiếu đến các phương thức.
User-defined Reference
Types
Kiểu được định nghĩa trong mã nguồn và được lưu như là
kiểu tham chiếu. Trong C#, nó có nghĩa là một lớp.
Boxed Value Types Một kiểu giá trị được bọc thành một kiểu tham chiếu vì thế
nó có thể được lưu trong heap.
Chúng ta không thể liệt kê tât cả các kiểu giá trị ở đây, bởi vì chúng sẽ được bàn kĩ trong
chương 2. Trong C#, mỗi kiểu có sẵn được nhận dạng bởi trình biên dịch ánh xạ đến một

thu hồi bộ nhớ của các chương trình thực thi. Từ trước đến giờ có hai công nghệ được sử
dụng cho việc huỷ bộ nhớ trong Windows, những tiến trình này được yêu c
ầu từ hệ
thống:
• Ứng dụng tự làm điều này một cách thủ công.
• Tạo một bộ đếm tham chiếu đến đối tượng.
Việc mã ứng dụng chịu trách nhiệm thu hồi vùng nhớ là một cộng nghệ dùng ở mức thấp,
hoặc những ngôn ngữ thực thi cấp cao như C++. Nó mang tính hiệu quả cao, nó có thuận
lợi là tài nguyên sẽ được giải phóng ngay khi không còn cần thiết. Một bất lợi lớn là nó
thường xuyên sinh lỗi. Mã nguồn luôn phải chỉ rõ cho hệ thống biết khi nó không cần
dùng bộ nhớ đó nữa . Dễ dàng nhìn ra rằng kết qu
ả có thể dẫn đến rò rỉ bộ nhớ.
Mặc dù các môi trường phát triển hiện đại có cung cấp một số công cụ giúp đỡ trong việc
phát hiện sự rò rỉ bộ nhớ, nhưng rất khó theo vết, bởi vì nó không có hiệu lực cho đến khi
có một khối lượng lớn bộ nhớ bị rò rỉ: Windows buộc phải ngưng các tiến trình xử lí. Tại
thời điểm này máy tính chậm đ
i thấy rõ một sự trả giá cho các yêu cầu bộ nhớ.
Việc duy trì một bộ đếm các tham chiếu là một ân huệ trong COM. Ý tưởng này cho rằng
mỗi thành phần COM chứa một bộ đếm xem có bao nhiêu ứng dụng đang chứa tham
chiếu đến nó. Khi bộ đếm này xuống đến zero, Thành phần có thể tự hủy nó và giải
phóng vùng nhớ cũng như các tài nguyên tương ứng. Vấn đề ở đây là nó vẫn lệ thu
ộc vào
sự thông báo của các ứng dụng khi chúng không còn dùng đến các thành phần này nữa.
Trong một vài trường hợp, nó có khả năng tạo ra một vấn đề nghiêm trọng hơn là sự kiểu
rò rỉ C++ thông thường, bởi vì đối tượng COM có thể nằm trong một tiến trình của riêng
nó, điều này có nghĩa là nó sẽ không bao giờ được hủy bởi hệ thống (chí ít trong rò rỉ
kiểu C++, hệ thống có thể giành lại toàn bộ vùng nh
ớ khi tiến trình kết thúc).
Thời gian chạy .NET hoàn toàn phụ thuộc vào garbage collector instead. Đây là một
chương trình hỗ trợ việc thu dọn bộ nhớ. Trong ý tưởng này tất cả các yêu cầu bộ nhớ

Một điều quan trọng là code-based security có thể làm giảm nguy cơ liên quan đến việc
chạy các đoạn mã có xuất xứ không rõ ràng (chẳ
ng hạn như mã mà bạn downloaded từ
Internet). Một ví dụ, nếu mã được chạy dưới quyền administrator, nó có thể sử dụng
code-based security để khai báo rằng mã không còn cho phép thực thi trong những kiểu
mà quyền administrator hỗ trợ như: không thể đọc hoặc viết lên các biến môi trường, đọc
hoặc viết lên registry, không truy cập vào các đặc trưng trong .NET.
Security sẽ được bàn kĩ hơn trong chương 23.
Application Domains
Application domains là một cách tân quan trọng trong .NET và nó được thiết kế để có thể

dễ dàng xử li các vấn đề khi chạy các ứng dụng cần sự biệt lập với các ứng dụng khác
nhưng vẫn có thể thông tin với các ứng dụng khác. Một ví dụ cổ điển đó lá một ứng dụng
web server application, nó phải phản hồi lại với một số lượng các yêu cấu từ các trình
duyệt. Chắc chắn rằng sẽ tồn tại cùng lúc nhiều thành phần có kh
ả năng phản hồi để phục
vụ cho các yêu cầu đó.
Trước thời .NET, sự lựa chọn giữa cho phép các thể hiện đó có thể dùng trong một tiến
trình, cái mà sẽ mang lại sự rủi ro có thể làm giảm độ an toàn của trang web, hay là cho
phép các thể hiện đó chạy trên các tiến trình biệt lập, cái mà sẽ mang lại sự gia tăng sự
thực thi.
Giờ đây, đó là sự biệt lậ
p mã thông qua các tiến trình. Khi bạn kích khởi một ứng dụng
mới, nó sẽ chạy trong ngữ cảnh của tiếnt trình. Các tiến trình Windows độc lập nhau
thông qua vùng địa chỉ. Trong ý tưởng này mỗi tiến trình sẽ có sẵn 4 gigabytes bộ nhớ ảo
để chữa dữ liệu và mã thực thi (4GB là dành cho hệ thống 32-bit; hệ thống 64-bit có thể
nhiều hơn). Windows gián tiếp thực hiện cơ chê mở rộng để ánh xạ bộ nhớ ả
o này với bộ
nhớ vật lí thật hay đĩa. Mỗi tiến trình sẽ có sự ánh xạ khác nhau, sao cho các vùng nhớ
vật lí thật sự không trùng lấp nhau. Nó được minh họa bởi sơ đồ sau:

một tiến trình được chia thành một số các application domains. Mỗi application domain
sẽ trả lời cho một ứng dụng đơn, và các loạt thực thi sẽ hoạt động như là một application
domain độc lập:

Nếu các thực thi cúng sử dụng chung một vùng nhớ, rõ ràng chúng có thể dùng chung dữ
liệu, bởi vì trên lí thuyết chúng có thể truy xuất trục tiếp dữ liệu của nhau. Tuy nhiên đó
chỉ là nguyên tắc, CLR sẽ bảo đảm rằng
điều này sẽ không xảy ra trong thực tế bằng cách
kiểm tra kỹ lưỡng mã trong mỗi ứng dụng, để chắc rằng chúng không lạc ra khỏi vùng dữ
liệu của chúng. Trước tiên hầu như các trò bịp quá đáng sẽ bị loại bỏ, sau đó ứng dụng có
thể hoạt động và không phải kích hoạt nó.
Thật sự, nó hoàn toàn có thể làm được điều này vì sự định kiểu mạnh củ
a IL. Trong nhiều
trường hợp, nếu mã thật sự dùng kiểu không quản chẳng hạn như các con trỏ, kiểu dữ liệu
đang dùng sẽ bảo đảm vùng nhớ sẽ được truy cập hợp lí. ví dụ, kiểu mảng .NET sẽ tiến
hành kiểm tra và bảo đảm rằng các thao tác trên mảng đều nằm trong phạm vi cho phép.
Nếu một thực thi cần trao đổi thông tin với các thực thi chạy trong các application
domain khác chúng phải gọi dịch v
ụ điều khiển từ xa của .NET.
Mã được kiểm tra xem có truy cập dữ liệu ngoài application domain không được gọi là
memory type-safe. Như vậy mã này có thể hoạt động cùng với mã được bảo vệ ở các
application domains khác nhau trong cùng một tiến trình.
Bẫy lỗi thông qua các ngoại lệ
.NET được thiết kế để đơn giản hoá quá trình bẫy lỗi thông qua các ngoại lệ. Những nhà
phát triển C++ nên biết rằng, bởi vì IL là hệ thống định ki
ểu mạnh, nó không thực thi các
mối kết hợp bất lợi thông qua các ngoại lệ trong IL, đây là cách được đưa ra trong C++.
Tất nhiên khối finally cũng được hỗ trợ trong .NET và C#.
Chúng ta sẽ bàn kĩ về ngoại lệ trong chương 4. Sơ qua một chút, ý tưởng ở đây là một
vùng mã được thiết kế như là các thủ tục quản ngoại lệ, mỗi đoạn mã có thể giải quyết

được sử dụng bởi trình biên dịch.
Attributes được hỗ trợ trong .NET - và vì thế giờ đây nó được hỗ trợ trong C++, C#, và
VB.NET. Một cái mới là các attribute trong .NET là một cơ chế cho phép bạn có thể định
nghĩa các attribute của riêng bạn trong mã nguồn. Các attribute tự định nghĩa này có thể
thay thế cho các siêu dữ liệu của các phương thức và kiểu dữ liệu tương ứng. .Do tính độc
lập ngôn ngữ của .NET mà các attribute có thể được định nghĩa trong một ngôn ngữ và
có thể đọc bằng mã ở các ngôn ngữ khác.
Attributes sẽ được bàn trong chương 5 của cuốn sách này.


Nhờ tải bản gốc

Tài liệu, ebook tham khảo khác

Music ♫

Copyright: Tài liệu đại học © DMCA.com Protection Status