Lập trình với C#: Chương 1 (Phần II)

Common Language Runtime

Trung tâm của .NET framework là môi trường thời gian chạy, gọi là Common Language Runtime (CLR) hoặc .NET runtime. Mã của các điều khiển trong CLR thường là mã có quản.

Tuy nhiêu, trước khi được thực thi bởi CLR, mã được phát triển trong C# (hoặc các ngôn ngữ khác) cần phải được biên dịch.Quá trình biên dịch trong .NET xảy ra theo hai bước:

  1. Dịch mã nguồn thành Microsoft Intermediate Language (MSIL)

  2. Dịch IL thành mã nền cụ thể bởi CLR

Mới nhìn có vẻ hơi dài dòng. Nhưng thật sự, một tiến trình dịch hai mức là rất cần thiết, bởi vì trạng thái của Microsoft Intermediate Language (mã có quản) là chìa khóa cung cấp nhiều lợi ích trong .NET.

Các lợi ích của mã có quản

Microsoft Intermediate Language (thường được viết tắt là”Intermediate Language”, hay “IL”) tương tự như ý tưởng về mã Java byte, nó là một ngôn ngữ cấp thấp với những cú pháp đơn giản (dựa trên cơ sở mã số hơn là text), chính điều này sẽ làm cho quá trình dịch sang mã máy nhanh hơn. Hiểu kĩ các cú pháp này sẽ mang lại những lợi ích đáng kể.

Độc lập nền

Trước tiên, nó có nghĩa là các file chứa mã lệnh có thể chạy trên bất kì nền nào, vào thời gian chạy trình biên dịch cuối sẽ hoạt động và mã có thể chạy trên một nền cụ thể. Nói cách khác việc dịch mã nguồn sang Intermediate Language cho phép độc lập nền trong .NET, nó giống như cách dịch mã nguồn sang Java byte code cung cấp sự độc lập nền trong Java.

Bạn cũng nên biết rằng sự độc lập nền của .NET chỉ là trên lí thuyết bởi vì tại thời điểm này, .NET chỉ có sẵn trong Windows. Tuy nhiên việc chuyển .NET sang những nền khác đang được khảo sát tỉ mỉ (xem ví dụ Mono project, một sự cố gắng tạo một thực thi mã nguồn mở trong .NET, tại địa chỉ  http://www.go-mono.com/).

Sự cải tiến trong thực thi

Mặc dù chúng ta đã so sánh với Jave, IL thật sự có một chút khả quan hơn Java. IL luôn là trình biên dịch Just-In-Time, ngược lại Java byte code thì thường là thông dịch. Một trong những bất lợi của Java là vào lúc thực thi quá trình dịch từ java byte code sang mã máy tốn nhiều tài nguyên.

Thay vì phải dịch toàn bộ ứng dụng một lần, trình biên dịch JIT sẽ biên dịch từng phần mã khi nó được gọi. Khi mã được dịch rồi, mã kết quả sẽ được giữ lại cho tới khi thoát khỏi ứng dụng, chính vì thế nó không phải biên dịch lại trong lần chạy kế tiếp. Microsoft quả quyết rằng cách xử lí này có hiệu lực cao hơn là dịch toàn bộ ứng dụng, bởi vì có trường hợp một khối lượng lớn mã của ứng dụng không bao giờ được sử dụng trong thời gian chạy. Khi sử dụng trình biên dịch JIT , các đoạn mã này sẽ không bao giờ được dịch.

Chính vì thế chúng ta hi vọng rằng mã IL sẽ thực thi nhanh như là mã máy. Microsof  cam kết chúng ta sẽ có một thay đổi lớn trong thực thi. Lời lí giải là, là lần dịch cuối cùng trong thời gian chạy, trình biên dịch JIT sẽ biết chính xác loại vi xử lí mà chương trình sẽ chạy. Có nghĩa là nó có thể tối ưu mã thi hành cuối cùng bằng cách tham chiếu đến các đặc trưng của từng các bộ lệnh ứng với các loại vi xử lí đó.

Các trình biên dịch truyền thống đều có tối ưu mã, nhưng chúng chỉ có thể tối ưu độc lập không quan tâm đến loại vi xử lý mà chương trình sẽ chạy. Bởi vì trình biên dịch truyền thống biên dịch toàn bộ ứng dụng sang mã máy trước khi thực thi. Có nghĩa là trình biên dịch không hề biết loại vi xử lí mà chương trình sẽ được chạy, chẳng hạn nó có thể là một vi xử lí tương thích x86 hoặc một vi xử lí Alpha. Visual Studio 6, tối ưu cho cho một máy tương thích Pentium, bởi vậy mã mà nó sinh ra không đem lại  lợi ích gì đối với các đặc trưng phần cứng của vi xử lí Pentium III. Trong khi đó, trình biên dịch JIT có thể thực hiện tối ưu giống như Visual Studio 6, ngoài ra nó còn có thể tối ưu cho các loại vi xử lí cụ thể mà mã chương trình sẽ chạy.

Tương hoạt giữa các ngôn ngữ

Chúng ta đã biết cách thức IL cho phép độc lập nền, trình biên dịch JIT có thể cải thiện quá trình thực thi. Tuy nhiên, IL cũng làm cho tương hoạt giữa các ngôn ngữ trở nên dễ dàng hơn. Bạn có thể biên dịch IL từ một ngôn, và mã này sau đó có thể tương hoạt với IL được biên dịch bởi một ngôn ngữ khác.

Bây giờ chắc bạn đang tự hỏi rằng những ngôn ngữ nào có thể tương tác với C# trong .NET, hãy xem qua các ngôn ngữ biết .NET phổ biến sau.

VB.NET

Visual Basic đã được tân trang lại để có thể tương thích với công nghệ .NET. Từ việc phát triển Visual Basic trong những năm gần đây cho thấy rằng trong các phiên bản trước, Visual Basic 6, nó không tương thích với lập trình .NET. Ví dụ, nó đặt nặng vấn đề tích hợp COM, và nó chỉ đưa ra các sự kiện để phát triển, hầu hết mã nền không có sẵn trong mã nguồn. Không những thế, nó không thực sự hỗ trợ tính thừa kế và các kiểu dữ liệu chuẩn của Visual Basic không tương thích với .NET.

Visual Basic đang được hoàn thiện trong Visual Basic .NET, cũng đừng ngạc nhiên khi sự thay đổi này xảy ra trên một diện rộng. Về phương diện thực hành bạn có thể xem VB.NET như là một ngôn ngữ mới. Mã VB 6 không không thể được biên dịch trong như mã VB.NET. Sự chuyển đổi từ lập trình VB 6 sang VB.NET yêu cầu một sự thay đổi lớn về mã. Tuy nhiên hầu hết các sự thay đổi này có thể được thực hiện một cách tự động bởi Visual Studio .NET (sự cải tiến của VS cho việc sử dụng .NET). Nếu bạn cố gắng đọc một đề án VB 6 trong Visual Studio .NET, nó sẽ cải tiến đề án của bạn, có nghĩa là nó sẽ viết lại mã nguồn VB 6 thành mã nguồn VB.NET. Điều đó có nghĩa là việc này sẽ gặp rắc rối khi bạn cắt ngang, bạn sẽ phải kiểm tra lại mã VB.NET mới để chắc rằng đề án của bạn vẫn chạy đúng.

Một hiệu ứng phụ là không còn khả năng biên dịch .NET sang mã thực thi. VB.NET chỉ biên dịch sang IL, giống như C#. Nếu như bạn muốn tiếp tục mã hóa trong VB 6, bạn có thể làm như vậy, nhưng khi mã thực thi quá dài nó sẽ lờ đi .NET Framework, và bạn cần phải giữ lại Visual Studio 6 đã cài đồng thời phải hoàn toàn tin vào môi trường phát triển trong Visual Studio.

Managed C++

Vào lúc đó trong Visual C++ 6, C++ đã có một khối lượng lớn các mở rộng của Microsoft trong Windows. Với Visual C++ .NET, các mở rộng này được tăng thêm cho việc hỗ trợ .NET framework. Có nghĩa là mã nguồn C++ sẽ vẫn tiếp tục được dịch sang mã máy không có gì khác biệt. Cũng có nghĩa là nó sẽ chạy độc lập trong môi trường .NET. Nếu bạn không muốn mã C++ của bạn chạy trong môi trường .NET Framework, bạn có thể đơn giãn đặt dòng lệnh sau vào đầu mã nguồn của bạn:

#using 

Bạn cũng có thể bỏ qua cờ /clr trong trình biên dịch, cờ này cho biết rằng bạn muốn biên dịch sang mã có quản, và nó sẽ phát ra IL thay vì mã máy. Có một điều thú vị trong C++ khi bạn biên dịch sang mã có quản, trình biên dịch có thể phát ra các IL có nhúng các mã máy. Điều này có nghĩa là bạn có thể pha trộn kiểu có quản và kiểu không quản trong mã C++. Bằng cách mã C++:

class MyClass
{

Định nghĩa cho một lớp trong C++ , trong khi đó mã:

__gc class MyClass
{

sẽ cho bạn một lớp có quản, giống như việc bạn viết một lớp trong C# hay VB.NET. Thật vậy, một thuận lợi của managed C++ so với C# là bạn có thể gọi các lớp không quản C++ từ mã có quản C++ bỏ qua tương thích COM.

Trình biên dịch sẽ phát ra một lỗi nếu bạn cố gắng dùng những đặc trưng mà mã có quản của .NET không hỗ trợ trong (ví dụ, khuôn mẫu hay đa thừa kế). Bạn cũng sẽ nhận ra rằng bạn sẽ phải dùng các đặc trưng không thuần C++ (chẳng hạn từ khoá __gc trong ví dụ trên) khi sử dụng các lớp có quản.

Bởi vì trong VC++ cho phép giải phóng bộ nhớ thủ công dưới dạng một con trỏ, trình biên dịch C++ không thể phát ra mã cho kiểu bộ nhớ an toàn CLR. Nếu ứng dụng của bạn thật sự cần phải nhận dạng kiểu bộ nhớ an toàn CLR, bạn cần phải viết mã nguồn trong các ngôn ngữ khác (như C# hay VB.NET).

J++ and J#

J++ vẫn được hỗ trợ cho chỉ vì mục đích tương thích trước đây. Microsoft không còn phát triển bất kì nền tảng nào hỗ trợ việc biện dịch sang máy Java ảo. Thay vì đó, Microsoft phát triển hai công nghệ tách biệt Java/J++ phát triển bên dưới ngọn cờ JUMP (Java User Migration Path) và “JUMP trong .NET”.

Công nghệ đầu tiên là Visual J#. Về bản chất nó được thêm vào Visual Studio.NET để cho phép bạn viết và biên dịch mã J++. Sự khác biệt đó là thay vì biên dịch sang một Java Virtual Machine, J# sẽ biên dịch sang IL, vì vậy nó sẽ hoạt động như là một ngôn ngữ của .NET. Ngừơi dùng J# sẽ có thể được hưởng các thuận lợi của các đặc tính của VS.NET. Microsoft tin răng người dùng J++ sẽ nhanh chóng nhận ra điều đó nếu họ thích làm việc trong với .NET.

Sự lựa chọn thứ hai là công cụ tự động hỗ trợ việc chuyển mã J++ sang mã C#. Sự giống nhau giữa J++ và C# làm cho việc chuyển đổi này trở nên dễ dàng hơn.

Không giống như J# cũng không như các công cụ chuyển đổi ngôn ngữ có sẵn như là một phần của .NET hay trong Visual Studio. NET, thay vì thế nó được cung cấp riêng. Để biết thêm thông tin liên hệ http://msdn.microsoft.com/visualj/.

Scripting languages

Scripting languages đâu đó vẫn còn tồn tại, dù rằng về mặt tổng quát, tầm quan trọng của chúng đã giảm sút cùng với sự ra đời của .NET. JScript, được cải tiến lên JScript.NET. ASP.NET (một cải tiến từ ASP dành cho .NET, giải thích sau) các trang có thể được viết bằng JScript.NET, và bây giờ nó có thể chạy trên JScript.NET như là một ngôn ngữ biên dịch hơn là một ngôn ngữ thông dịch và nó có thể tạo ra các mã kiểu mã JScript.NET mạnh hơn. Với ASP.NET không có lí do gì để dùng scripting languages trên cac trang web server-side. VBA vẫn được sử dụng như là một ngôn ngữ cho Microsoft Office và Visual Studio macros.

COM and COM+

COM và COM+ không là công nghệ chính của .NET, bởi vì các thành phần cơ bản của chúng không thể dịch sang IL (mặc dù vẫn có thể làm điều đó khi tổ chức thành phần COM bằng mã C++). Tuy nhiên COM+ vẫn còn là một công cụ quan trọng, từ khi đặc tính của nó được nhân lên trong .NET. Ngoài ra, thành phần COM vẫn còn làm việc và .NET kết hợp chặc chẽ các đặc trưng tương hoạt COM để mã có quản có thể gọi đến COM và ngược lại (sẽ được bàn thêm ở chương 17).

(Còn tiếp)