Giáo trình kỹ thuật lập trình C#

Chia sẻ: Vũ Trọng Lân | Ngày: | Loại File: DOC | Số trang:219

0
200
lượt xem
93
download

Giáo trình kỹ thuật lập trình C#

Mô tả tài liệu
  Download Vui lòng tải xuống để xem tài liệu đầy đủ

Tôi muốn nhấn mạnh rằng đừng bao giờ xem xét ngôn ngữ C# một cách tách biệt, nó luôn đồng hành với "Bộ khung .NET". C# là một trình biên dịch hướng .NET, nghĩa là tất cả các mã của C# luôn luôn chạy trên trên môi trường .NET Framework. Điều đó dẫn đến 2 hệ quả sau: Cấu trúc và các lập luận C# được phản ánh các phương pháp luận của .NET ngầm bên dưới. Trong nhiều trường hợp, các đặc trưng của C# thậm chí được quyết định dựa vào các đặc trưng của .NET, hoặc thư viện lớp cơ...

Chủ đề:
Lưu

Nội dung Text: Giáo trình kỹ thuật lập trình C#

  1. Giáo trình Lập trình với C#
  2. Chương 1 - Kiến trúc của C# và .NET Chương 2 - Căn bản C# Chương 3 - Hướng đối tượng trong C# Chương 4 - Những chủ đề tiến bộ trong C# Chương 5 - C# và các lớp cơ sở Chương 6 - Lập trình trong môi trường .NET Chương 7 - Windows Applications Chương 8 - Assemblies Chương 9 - Truy cập cơ sở dữ liệu với .NET Chương - Viewing .NET Data 10 Chương - Thao tác XML 11 Chương - File and Registry Operations 12 Chương - Làm việc với Active Directory 13
  3. Biên dịch từ cuốn Professional C#, 2nd Edition, Xuất bản bởi Wrox Press Ltd . Chương 1: C# và kiến trúc .NET Tổng quan: Tôi muốn nhấn mạnh rằng đừng bao giờ xem xét ngôn ngữ C# một cách tách bi ệt, nó luôn đ ồng hành với "B ộ khung .NET". C# là một trình biên dịch hướng .NET, nghĩa là tất cả các mã của C# luôn luôn chạy trên trên môi tr ường .NET Framework. Điều đó dẫn đến 2 hệ quả sau: • Cấu trúc và các lập luận C# được phản ánh các phương pháp luận của .NET ngầm bên dưới. • Trong nhiều trường hợp, các đặc trưng của C# thậm chí được quyết định dựa vào các đ ặc tr ưng của .NET, hoặc thư viện lớp cơ sở của .NET. Chính bởi tầm quan trọng của .NET, nên các bạn cần phải biết sơ qua về .NET trước khi đi vào ngôn ng ữ C#. Đây cũng chính là mục đích của chương này. Chúng ta sẽ tìm hiểu xem chuyện gì sẽ xảy ra khi mã của các ngôn ngữ hướng .NET (bao g ồm C#) đ ược biên dịch và th ực thi. Đây là một lĩnh vực rộng, chúng ta sẽ tìm hiểu kĩ hơn về Microsoft Intermediate Language (MS-IL), ngôn ngữ trung gian trong .NET mã của các ngôn ngữ khác đều phải được biên dịch về ngôn ng ữ này tr ước khi thực thi. C ụ th ể chúng ta s ẽ tìm hiểu xem cách thức mà MS-IL với phần dùng chung Common Type System (CTS) và Common Language Specification (CLS) có thể cung cấp cho chúng ta sự tương hoạt giữa các ngôn ngữ hướng .NET. Chúng ta cũng s ẽ trình bày các ngôn ng ữ biết .NET khác bao gồm VB và C++. Sau đó chúng ta sẽ xem xét các đặc trưng khác của .NET, bao gồm các assembly, các namespace, và th ư vi ện l ớp c ơ b ản của .NET. Chúng ta sẽ kết thúc chương này bằng việc liệt kê vắn tắt về các loại ứng dụng mà chúng ta có thể t ạo ra trong C#. Mối quan hệ giữa C# và .NET C# là một ngôn ngữ lập trình mới, và được biết đến với hai lời chào: • Nó được thiết kế riêng để dùng cho Microsoft's .NET Framework (Một nền khá mạnh cho s ự phát tri ển, tri ển khai, hiện thực và phân phối các ứng dụng) • Nó là một ngôn ngữ hoàn toàn hướng đối tượng được thiết kế dựa trên kinh nghi ệm của các ngôn ng ữ hướng đ ối tượng khác. Một điều quan trọng cần nhớ C# là một ngôn ngữ độc lập. Nó được thiết kế để có thể sinh ra mã đích trong môi tr ường .NET, nó không phải là một phần của .NET bởi vậy có một vài đặc trưng được hỗ trợ bởi .NET nhưng C# không hỗ tr ợ và bạn cũng đừng ngạc nhiên khi có những đặc trưng C# hỗ trợ mà .NET không hỗ tr ợ (chẳng hạn như quá t ải toán t ử) Để tạo được những ứng dụng mang tính hiệu quả cao, chúng ta sẽ xem qua về hoạt động của .NET 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 (MS-IL) 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 ể.
  4. Độ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
  5. 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). Assemblies Một assembly là một đơn vị luận lí chứa mã đã được biên dịch sang .NET. Chúng ta s ẽ bàn kĩ về các assemblie trong ch ương 8, ở đây chúng ta sẽ nói sơ về nó.
  6. Một assembly là một tự mô tả đầy đủ, và nó giống một đơn vị luận lí hơn là một đơn vị vật lí, đi ều đó có nghĩa là nó có th ể chứa trong nhiều file (thật vậy các assemblie động được lưu trong bộ nhớ không phải trong file). Nếu một assembly đ ược lưu trong nhiều file, thì sẽ có một file chính chứa các con trỏ và các mô t ả về các file khác c ủa assembly. Chú ý rằng, câu trúc assembly được dùng chung cho cả mã thi hành và mã thư vi ện. Sự khác bi ệt duy nhất là assembly thi hành chứa lối vào chương trình chính trong khi assembly thư viện thì không có. Một điểm quan trọng trong các assembly là chúng chứa metadata dùng đ ể mô t ả các ki ểu và ph ương thức đ ược đ ịnh nghĩa trong mã tương ứng. Một assembly, tất nhiên cũng chứ assembly metadata dùng để mô t ả chính assembly đó. Assembly metadata này, chứa một vùng đựơc hiểu như là manifest, cho phép kiểm tra phiên bản và tình trạng của assembly. ildasm, một tiện ích có sẵn của Windows, có thể dùng để nghiên cứu nội dung của một assembly, bao gồm manifest metadata. Chúng ta sẽ lấy vi dụ về ildasm trong chương 8. Thật vậy một assembly chứa metadata của chương trình nghĩa là các ứng dụng hoặc các assembly khác có th ể g ọi mã trong môt assembly mà không cần tham chiếu đến Registry, hoặc một dữ liệu nguồn khác,. Một đi ểm quan tr ọng trong cách làm của COM cũ, các GUID của các thành phần và giao diện interfaces không thể đ ạt đ ược t ừ Registry. Việc dàn trải dự liệu thành 3 định vị khác nhau đồng nghĩa với việc tạo ra mối nguy hiểm trong đ ồng bộ hoá, nó ngăn không cho các thành phần khác sử dụng. Với assemblies, sẽ không còn những mối nguy hi ểm như vậy, bởi vì t ất các các metadata được lưu trong bộ lệnh thi hành của chương trình. Chú ý rằng dù cho các assemblie đ ược l ưu thành một vài file, chúng v ẫn không gây vấn đề gì về đồng bộ hoá dữ liệu. Đó là vì nhờ vào file assembly chính, file này chứa đ ường d ẫn, các thông tin chi tiết, mã băm, và nội dung của các file khác, điều đó có nghĩa là nếu một file bị thay th ế, hay b ị phá ho ại, nó s ẽ đ ược tìm ra và sẽ không cho load. Assemblies bao gồm 2 loại: các shared và private assembly. Private Assemblies Private assemblies là kiểu đơn giản nhất. Nó chứa phần mềm và chỉ được dùng cho phần mềm đó. Với phần mô t ả này bạn có thể chứa đựng các private assemblie hòng cung cấp cho một ứng dụng kiểu thực thi và một s ố thư vi ện, các thư vi ện này chứa mã sẽ được thi hành bởi ứng dụng đó. Hệ thống đảm bảo rằng private assemblies sẽ không được dùng bởi phần mềm khác, bởi vì một ứng dụng chỉ có thể load private assemblies trong cùng folder với chương trình chính hoặc là trong một thư mục con c ủa nó. Chúng ta không thể tin cậy rằng tất cả các phần mềm luôn được cài đặt trong thư mục của nó, nghĩa là s ẽ không bao gi ờ có chuyện một gói phần mềm ghi đè, sửa chữa hoặc vô tình load một private assemblies dành ri ền cho một gói khác. V ậy làm sao để các Private assemblie chỉ được dùng bởi gói phần mềm mà nó mô tả? Cần có một cơ chế bảo vệ, sao cho khi một s ản phẩm thương mại khác cài đè lên một phiên bản assembly mới (chưa kể đến các chương trình đ ựơc thi ết k ế đ ể phá ho ại), thì sẽ không có chuyện tranh chấp tên. Nếu có sự trùng tên trong các assembly, đ ều đó không quan tr ọng và các ứng d ụng ch ỉ có thể nhìn thấy một bộ các assembly. Bởi vì một private assembly là một tự định nghĩa trọn vẹn, tiến trình xử lí cực kì đ ơn gi ản. Bạn đ ơn gi ản thay thế các file thích hợp vào thư mục thíhc hợp trong file hệ thống (Không cần phải đăng kí trong registry). Ti ến trình này đ ược g ọi là zero impact (xcopy) installation. Shared Assemblies Shared assemblies được dành cho cácc thư viện công cộng có thể dùng cho bất kì ứng dụng nào. B ởi vì b ất kì ứng d ụng nào cũng có thể truy xuất một shared assembly, cần phải có các cơ chế để bảo vệ các r ủi ro sau: • Tranh chấp tên, khi một công ty tạo ra các shared assembly trùng tên với các shared assembly s ẵn có c ủa b ạn. V ề mặt lí thuyết mã của bạn có thể truy xuất vào cả hai assembly này song đây có thể là một vấn đ ề phức t ạp. • Lỗi của một assembly có thể bị ghi đè bởi một phiên bản khác của cùng same assembly - một phiên bản mới không tương thích với những gì sẵn có. Giải pháp cho những vấn đề trên là đặt các shared assembly trong một cây thư mục đ ặt bi ệt c ủa h ệ th ống, có th ể xem nh ư là assembly cache toàn cục. Không giống như các private assembly, nó không đơn giản là copy assembly sang một thư mục thích hợp - nó cần được cài đặt rõ ràng vào cache. Tiến trình này có thể đ ược thực thi b ởi m ột s ố ti ện ích c ủa .NET, bao g ồm luôn quá trình kiểm tra trên assembly, tương tự như cài đặt một thư mục trong assembly cache đ ể đ ảm bảo tính toàn v ẹn c ủa assembly. Để tránh tranh chấp tên, shared assemblies đưa ra một được quản lí dựa trên một khóa mật mã chính. Tên này đ ược g ọi là strong name, được bảo đảm về tính độc nhất, và phải được trích dẫn bởi ứng dụng muốn tham chi ếu đ ến một shared assembly. Vấn đề về tương thích với lỗi do ghi đè một assembly được đánh địa chỉ theo thông tín phiên bản trong assembly manifest, và cho phép cài đặt song song.
  7. Reflection Từ khi các assembly được lưu dưới dạng metadata, bao gồm chi tiết về tất cả các ki ểu và thành viên c ủa nh ững ki ểu này, thì nó có thể được truy xuất được các metadata programmatically. Đ ể bi ết chi ti ết hơn, xin hãy xem reflection - mã qu ả có th ể xem xét các mã quản khác, hoặc xem xét chính nó, để nhận ra các thông tin về mã. Bạn có thể dùng các attribute, đ ể có th ể s ử dụng phương thức trong lúc chạy điều này tốt hơn là trong lúc biên dịch. 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 đ ối t ượng, dù vậy chúng vẫn còn được quan tâm để có thể thực thi chéo. Chúng ta cần tìm hiểu một chút về thực thi chéo ngôn ng ữ. Trước tiên chúng ta cần hiểu chính xác thực thi ngôn ngữ chéo là gì. Sau cùng, COM cho phép các thành ph ần đ ược vi ết b ởi các ngôn ngữ khác nhau có thể thực thi chéo. COM, là một nhị phân chuẩn, cho phép các thành ph ần có th ể hi ểu nhau và có thể gọi các phương thức cũng như thuộc tính lẫn nhau mà không cần quan tâm đến ngôn ngữ đã t ạo ra chúng. Đ ể làm đ ược điều đó mỗi đối tượng phải có khả năng giao tiếp với thời gian chạy của COM, và phải có khả năng truy cập thông qua một giao diện. Các thành phần chỉ có thể giao tiếp với nhau trong thời gian chạy COM. Dù r ằng các thành ph ần c ủa COM có th ể giao tiếp với nhau bất chấp ngôn ngữ đã tạo ra chúng, tuy nhiên COM không hỗ tr ợ hoạt đ ộng thừa k ế, chính vì th ế nó đã đánh mất các thuận lợi của lập trình hướng đối tượng. Một vấn đề xảy ra khi bẫy lỗi là các thành thành phần phải được bẫy l ỗi trong ngôn ng ữ đã t ạo chúng, và b ạn không th ể bẫy lỗi từng bước trên các ngôn ngữ khác nhau. Vậy thực thi chéo ngôn ngữ được hi ểu như là các l ớp đ ược t ạo ra trong m ột ngôn ngữ có thể giao tiếp lẫn nhau với các lớp được tạo ra trong các ngôn ng ữ khác. Cụ thể là: • Một lớp được tạo ra trong một ngôn ngữ có thể thừa kế từ một lớp được viết trong một ngôn ng ữ khác. • Một lớp có thể chứa thể hiện của một lớp khác không quan tâm đến ngôn ngữ đã tạo ra hai l ớp đó. • Một đối tượng có thể gọi trực tiếp phương thức của một đối tượng khác được viết bởi một ngôn ng ữ khác. • Các đối tượng (hoặc các tham chiếu đến các đối tượng) có thể được truyền qua l ại gi ữa các hàm • Bạn có khả năng bẫy lỗi từng bước chương trình nguồn giữa các ngôn khác nhau Thật bất ngờ về những gì mà .NET và thực thi ngôn ngữ chéo đã làm được. Ti ện ích bẫy l ỗi t ừng đ ược gi ới thi ệu nh ư là kh ả năng của Visual Studio .NET IDE hơn là CLR. Sự khác biệt giữa kiểu dữ liệu giá trị và kiểu dữ liệu tham chiếu
  8. 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 cho phép mơ hồ ki ểu, tuy nhiên ch ỉ để có thể làm được như thể làm được như vậy thì trình biên dịch đã xác đ ịnh ki ểu bảo vệ ki ểu tr ước khi phát ra IL. Mặc dù, kiểu bảo vệ lúc đầu có thể sinh ra nhiều cản trở trong lập trình nhưng trong nhi ều tr ường hợp ki ểu bảo vệ s ẽ mang lại nhiều lợi ích to lớn trong các dịch vụ được cung cấp bởi .NET. Chẳng hạn các dịch vụ sau: • Language Interoperability • Garbage Collection • Security • Application Domains Hãy tìm hiểu xem tại sao kiểu dữ liệu mạnh lại là một trong những đặc tính quan tr ọng của .NET. Tầm quan trọng của Strong Data Typing đối với Language Interoperability Một khía cạnh quan trong của strong data typing là nếu một lớp xuất thân hoặc chứa một lớp khác thì nó cần phải biết tất cả các kiểu dùng trong các lớp đó. Thật vậy, nó đã từng các chướng ngại lớn trong vi ệc thực thi ngôn ng ữ chéo ở các h ệ thống không hỗ trợ trước đấy. Thông tin này không có sẵn trong các file thi hành và DLL chuẩn. Giả sử rằng một phương thức trong VB.NET được định nghĩa là sẽ trả về một Integer, một trong những kiểu dữ liệu chuẩn của VB.NET. C# không có kiểu dữ liệu có tên như vậy. Chúng ta chỉ có thể dùng phương thức này đ ể tr ả về một ki ểu của C# nết trình biên dịch biết cách ánh xạ kiểu VB.NET's Integer đến một trong những kiểu được định nghĩa trong C#. Vậy .NET đã làm việc đó như thế nào? Common Type System (CTS) Vấn đề về kiểu dữ liệu này được .NET giải quyết bằng cách dùng Common Type System (CTS). CTS định nghĩa các kiểu dữ liệu tiền định và có sẵn trong IL, vì thế tất các các ngôn ngữ hướng .NET framework s ẽ sinh ra mã cu ối trên c ơ s ở các kiểu dữ liệu này. Trong ví dụ trên, VB.NET's Integer thực tế là một 32-bit signed integer, được ánh xạ từ 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ự.
  9. Kiểu Giải thích 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 kiểu IL cài sẵn. Đi ều này cũng đúng cho c ả VB.NET. Common Language Specification (CLS) Common Language Specification hoạt động cùng với Common Type System để bảo đ ảm thực thi ngôn ng ữ chéo. CLS là một bộ con chuẩn mà tất cả các trình biên dịch hướng .NET đều phải hỗ trợ. Đều đó có nghĩa là các trình biên d ịch đ ều s ẽ h ỗ tr ợ tất cả những gì được định nghĩa trong CLS. Chú ý: Các bạn có thể viết các mã non-CLS, tuy nhiên những mã này không đảm bảo việc thực thi ngôn ng ữ chéo. IL là một ngôn ngữ phân biệt loại kí tự. Những nhà phát triển khi làm vi ệc với các ngôn ng ữ phân bi ệt lo ại kí t ự có kh ả năng tạo nên sự mềm dẻo khi đặt tên biến. VB.NET, lại không phải là ngôn ngữ phân biệt loại kí t ự. CLS xử lí vi ệc này bằng các ra hiệu cho CLS rằng mã không cho phép hai tên chỉ khác nhau về mặt loại kí t ự. Bởi vậy, mã VB.NET có th ể ho ạt đ ộng trong CLS. CLS hoạt động theo hai định hướng. Trước tiên nó là một trình biên dịch riêng không hỗ tr ợ đây đ ủ các đ ặc tr ưng c ủa .NET điều này khuyến khích sự phát triển của các ngôn biết .NET khác. Thứ hai, nó bảo đ ảm r ằng nếu bạn hạn ch ế các l ớp c ủa bạn trong những đặc tính của CLS, thì nó bảo đảm rằng các mã dùng trong những ngôn ng ữ khác có thể dùng các l ớp này. Nét đẹp của ý tưởng này là việc giới hạn trong những đặc tính của CLS chỉ nên áp dụng cho những thành phần public và protected của các lớp và chỉ dùng cho các lớp public. Trong các thành phần thực thi của các l ớp c ủa b ạn, b ạn có th ể vi ết các mã non-CLS nếu muốn, bởi các ngôn ngữ khác không bao giờ có thể truy cập vào những phần này. Chúng ta không đi vào chi tiết của CLS ở đây. Về mặt tổng quát CLS không ảnh hưởng nhi ều đến mã C# của bạn vì nó không có nhiều đặc tính khác CLS. Garbage Collection Garbage collector là một thành phần quản lí bộ nhớ của .NET, nó là một đáp án cho việc 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).
  10. 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ớ đều được cấp phát trên heap (điều này đúng cho t ất cả các ngôn ng ữ, trong .NET, CLR chứa nó trong vùng heap có quản cho tất cả các ứng dụng .NET s ử dụng). Thỉnh thoảng .NET s ẽ ki ểm tra xem vùng heap có quản có trở nên đầy chưa để nó tiến hành thu dọn, và nó g ọi đây là ti ến trình thu gôm rác. Trình thu d ọn rác sẽ kiểm tra các tham chiếu từ mã của bạn, ví dụ các tham chiếu từ mã của bạn đến các đ ối t ượng đ ược l ưu trên heap đ ược nhận dạng, nó có nghĩa là đối tượng đó vẫn còn tham chi ếu, các đối tượng không còn tham chi ếu nữa s ẽ bị huỷ. Trình thu gom rác hoạt động trong .NET bởi vì Intermediate Language đ ược thi ết k ế đ ể làm đi ều đó. Ph ải tuân th ủ các nguyên tắc sau, thứ nhất bạn chỉ có thể tham chiếu đến một đối tượng có sẵn bằng cách sao chép cac tham chi ếu có s ẵn, th ứ hai Intermediate Language bảo vệ kiểu, điều này có nghĩa là các tham chi ếu đ ến các đ ối t ượng có s ẵn luôn ch ứa đ ựng thông tín nhận dạng chính xác của đối tượng đó. C++ Có thể không sử dụng trình thu gom một cách máy móc, bởi vì C++ cho phép các con tr ỏ t ự do ép ki ểu. Một điều đặc biệt quản trọng là tính không định trước của trình thu gom rác. Hay nói cách khác, b ạn không th ể b ảo đ ảm được khi nào trình thu gôm rác sẽ được gọi; nó sẽ được gọi khi CLR cảm thấy cần (nếu bạn không thực hi ện l ời g ọi t ường minh). Bảo mật .NET thật sự xuất sắc trong việc bổ sung cơ chế bảo mật của Windows bởi vì nó hỗ trợ code-based security trong khi đó Windows chỉ thật sự hỗ trợ Role-based security. Role-based security là cơ sở để xác định tài khoản của các tiến trình đang thực thi, hay nói cách khác ai s ở hữu các ti ến trình đang thực thi. Code-based security là một cơ chế khác để xác định xem những mã nào và có bao nhiêu mã là đáng tin. C ảm ơn sự bảo vệ kiểu mạnh của IL, vì nhờ nó mà CLR có thể kiểm tra mã trước khi chạy trong một chế đ ộ bảo vệ đ ược đ ưa ra.NET cũng hỗ trợ một cơ chế những mã nào được phép phơi tra trong một cơ ch ế bảo mật nào đó. 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:
  11. Một cách tổng quat, bất kì tiến trình nào cũng chỉ có thể truy cập đến bộ nhớ thông qua mộ đ ịa chỉ ảo cụ thể - các ti ến trình không thể truy xuất trực tiếp bộ nhớ vật lí. Như vậy nó đơn giản là không cho phép một ti ến trình có thể truy xu ất đ ến vùng nhớ được cấp cho một tiến trình khác. Nó cung cấp một cơ chế bảo đảm rằng những ứng xử t ồi của mã không thể làm h ỏng bất kì thứ gì bên ngoài vùng địa chỉ của nó. (chú ý rằng trong Windows 9x, những cơ chế bảo vệ này không đ ươc thấu đáo như trong NT/2000/XP, vì thế về mặt lí thuyết các ứng dụng có khả năng phá hủy Windows do vi ết lên vùng nhớ không thích hợp). Các tiến trình không chỉ phục vụ như là cách để tạo nên sự tách biệt giữa các thể hi ện khác nhau. Trong hệ th ống Windows NT/2000, nó còn làm đơn vị để gán các giấy phép và đặc quyền bảo mật. Mỗi ti ến trình có một kí hi ệu bảo mật riêng, đ ể báo cho Windows biết chính xác các thực thi mà tiến trình cho phép. Cả hai phương pháp này đều có khả năng bảo mật tốt nhưng lại sinh ra một bất lợi lớn đó là thực thi. Thông th ường các ti ến trình sẽ hoạt động chung với nhau, bởi vậy cần phải có sự truyền thông giữa chúng. Ví dụ như đâu đó một ti ến trình g ọi m ột thành phần COM khả thi, và bởi vì được yêu cầu chạy trong tiến trình của chúng. Gi ống như cách mà COM vẫn làm. Khi đó các tiến trình không thể dùng chung bộ nhớ, một tiến trình phức tạp được sử dụng để sao chép dữ li ệu gi ữa các ti ến trình. Nó sẽ gây trở ngại lớin đến vấn đề thực thi. Nếu bạn muốn các thành phần có thể làm vi ệc với nhau mà không mu ốn ảnh hưởng đến vấn đề thực thi, cách duy nhất là sử dụng DLL-based components và mọi thứ s ẽ hoạt đ ộng trong cùng một vùng đã chỉ (đây là một việc mạo hiểm vì các thành phần ứng xử tồi sẽ làm hỏng t ất cả mọi thứ). Application domains được thiết kế như là một thành phần riêng biệt không gây ảnh hưởng đến vấn đề thực thi trong lúc các tiến trình trao đổi dữ liệu. Ý tưởng này cho rằng 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
  12. 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 một điêu kiện lỗi riêng (ví dụ, một file không đ ược tìm thấy, hoặc không được phép thực thi một số lệnh). Những điều kiện này có thể được định nghĩa kĩ hoặc sơ qua tuỳ bạn. Cấu trúc ngoại l ệ bảo đảm rằng khi một điều kiện sinh lỗi xảy ra, ngay lập tức luồn thi hành sẽ nhảy đến thủ t ục quản ngoại l ệ. Cơ cấu quản ngoại lệ tạo điều kiện thuận lợi để truyền cho một đối tượng thông tin chính xác về các đi ều ki ện sinh ngoại lệ và một thủ tục quản ngoại lệ. Đối tượng này có thể bao gồm một thông điệp thích hợp cho ng ười dùng và chi ti ết v ề n ơi phát sinh ngoại lệ. Hầu hết các cơ cấu quản ngoại lệ, bao gồm cả điều khiển của chương trình sẽ treo khi một ngoại l ệ đ ược phát sinh, đ ược quản bởi ngôn ngữ bậc cao (C#, VB.NET, C++), và không một lệnh IL nào hỗ trợ việc đó. Ví dụ C#, qu ản s ự ki ện thông qua các khối mã try{}, catch{}, finally{}, chúng ta sẽ bàn sau trong chương 4. Những gì mà .NET làm là cung cấp cơ sở cho phép các trình biên dịch hướng .NET hỗ tr ợ vi ệc qu ản ngo ại l ệ. C ụ th ể nó cung cấp một bộ các lớp .NET có thể miêu tả các ngoại lệ, và thực thi ngôn ngữ chéo cho phép truy ền các đ ối t ượng ngoại lệ cho các mã quản ngoại lệ, bất chấp mã quản ngoại lệ được viết trong ngôn ngữ nào. Sự đ ộc l ập ngôn ng ữ này không được hỗ trợ trong việc quản ngoại lệ của C++ lẫn Jave, mặc dù nó vẫn tồn tại giới hạn trong cơ cấu COM cho vi ệc qu ản lỗi: bao gồm việc trả về mã lỗi trong các phương thức và truyền các đối tượng lỗi. Thật vậy các ngoại l ệ đó đ ược qu ản m ột cách nhất quán trong các ngôn ngữ khác nhau nó đóng vai trò quyết đ ịnh trong phát tri ển đa ngôn ng ữ. Dùng các thuộc tính Attributes là một đặc trưng đã thân thuộc với những nhà phát triển C++ để viết các thành phần COM (thông qua vi ệc s ử dụng Microsoft's COM Interface Definition Language (IDL)) dù vậy nó không thân thi ện với những nhà phát tri ển Visual Basic hay Java. Attribute cung cấp thông tin mở rộng liên quan đ ến các mục trong chương trình có th ể đ ượ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. Các lớp .NET Framework Có lẽ một trong những lợi ích lớn nhất của viết mã có quản, ít nhất là đối với một nhà phát tri ển, đó là bạn có thể s ử d ụng thư viện lớp cơ sở của .NET. Thư viện lớp cơ sở của .NET là một tập hợp lớn các lớp mã có quản được viết bởi Microsoft, những l ớp này cho phép b ạn thao tác rất nhiều các tác vụ sẵn có trong Windows. Bạn có thể t ạo các l ớp của mình t ừ các l ớp có s ẵn trong th ư vi ện l ớp c ơ sở của .NET dựa trên cơ chế thừa kế đơn. Thư viện lớp cơ sở của .NET rất trực quan và rất dễ sử dụng. Ví dụ, để tạo một tiến trình mới, bạn đ ơn gi ản g ọi ph ương thức Start() của lớp Thread. Để disable một TextBox, bạn đặt thuộc tính Enabled của đối tượng TextBox là false. Thư viện này được thiết kế để dễ xài như là Visual Basic và Java. Tất nhiên là nó dễ s ử dụng hơn các l ớp c ủa C++: các v ỏ b ọc ngoài các hàm API thô như GetDIBits(), RegisterWndClassEx(), và IsEqualIID(). Mặt khác, những nhà phát triển C++ luôn dễ dàng truy cập đến các API, ngược lại những nhà phát tri ển Visual Basic và Java đã bị giới hạn trong những thao tác hệ thống cơ bản mà ngôn ngữ đã từng ngôn ngữ đã cung cấp s ẵn. Cái mới của thư vi ện lớp cơ sở .NET là kết hợp tính đơn giản của các thư viện Visual Basic và Java với hầu hết các đ ặc tính trong các hàm Windows API. Có nhiều đặc tính của Windows không sẵn có trong các lớp của thư viện .NET, trong tr ường hợp đó bạn cần phải gọi các hàm API, những đặc tính này thường là các đặc tính l ạ, ít s ử dụng. Những đ ặc tính thông d ụng đ ều đã đ ược h ỗ trợ đầy đủ trong thư viện lớp của .NET. Và nếu bạn muốn gọi một hàm API, .NET g ọi là "platform-invoke", c ơ ch ế này luôn bảo đảm tính đúng đắn của kiểu dữ liệu, vì vậy thao tác này không khó hơn việc gọi trực ti ếp t ừ mã C++, nó đ ược hỗ tr ợ cho cả C#, C++, và VB.NET.
  13. WinCV, một tiện ích Windows-based, bạn có thể dùng để tham khảo các lớp, cấu trúc, giao di ện, ki ểu li ệt kê trong th ư viện .NET base class. Chúng ta sẽ tìm hiểu WinCV trong chương 6. Dù rằng chủ đề của chương 5 bàn về các lớp cơ sở, nhưng thực tế, chúng tôi chỉ nói về các cú pháp của ngôn ng ữ C#, ch ủ yếu quyển sách này chỉ cho các bạn về cách dùng các lớp khác nhau trong thư vi ện .NET base class. M ột cách t ổng quát .NET base classes bao gồm các vấn đề: • Các đặc tính lõi cung cấp bởi IL (chủ yếu là về các kiểu dữ liệu trong CTS, Ch ương 5) • Hỗ trợ Windows GUI và controls (Chương 7) • Web Forms (ASP.NET, 16) • Data Access (ADO.NET, 10) • Directory Access (Chương 13) • File system và registry access (Chương 12) • Networking và web browsing (Chương 20) • .NET attributes và reflection (Chương 5) • Truy xuất vào hệ điều hành Windows (các biến môi trường vv..., Chương 23) • COM interoperability (18) Một cách tình cờ, hầu hết các thư viện lớp cơ sở của .NET được viết bằng C#! Các Namespace Namespace là cách mà .NET dùng để chống lại sự xung đột tên giữa các l ớp. Chẳng hạn nh ư tr ường hợp bạn có một l ớp mô tả khách hàng gọi là lớp Customer, và sau đó một người khác cũng có một lớp giống như vậy. Một namespace không chỉ là một nhóm các kiểu dữ liệu, mà nó làm cho tên của t ất cả các ki ểu dữ li ệu trong cùng m ột không gian tên sẽ có tiếp đầu ngữ là tên của namespace đó. Nó cũng cho phép một không gian tên n ằm trong m ột không gian tên khác. Ví dụ, hầu hết các hỗ trợ chung của các thư viện lớp cơ sở .NET đều nằm trong một không gian tên g ọi là System. Lớp cơ sở Array nằm trong không gian tên này có tên đầy đủ là System.Array. .NET yêu cầu tất cả các kiểu đều phải được định nghĩa trong một không gian tên, ví dụ bạn có thể đ ặt l ớp Customer của bạn trong một không gian tên gọi là YourCompanyName. Lớp này sẽ có tên đầy đủ là YourCompanyName.Customer. Nều một namespace không được khai báo rõ ràng, các kiểu sẽ được đặt vào một namespace toàn cục không tên. Microsoft khuyên rằng các hỗ trợ của bạn nên đặt vào một namespace ít nh ất là 2 cấp, cấp một là tên c ủa công ty c ủa b ạn, cấp hai là tên của công nghệ hoặc là phần mềm của gói sản phẩm đó, chẳng hạn như YourCompanyName.SalesServices.Customer. Làm như vậy trong hầu hết các trường hợp đảm bảo rằng, các lớp trong ứng dụng của bạn không xung đột tên với các lớp của các tổ chức khác. Chúng ta sẽ xem xét thêm về namespace ở chương 2. Tạo các ứng dụng .NET bằng C# C# có thể dùng để tạo các ứng dụng console: các ứng dụng thuần văn bản chạy trên DOS window. H ầu như bạn ch ỉ t ạo các ứng dụng console khi cần kiểm tra các thư viện lớp, hoặc cho các ti ến trình daemon Unix/Linux. Tât nhiên, b ạn cũng có th ể dùng C# để tạo các ứng dụng dùng cho các công nghệ tương thích .NET. Trong phần này, chúng ta xem qua v ề các ki ểu ứng dụng khác nhau có thể tạo ra bằng C#. Tạo các ứng dụng ASP.NET ASP là một công nghệ của Microsoft dùng để tạo các trang web có nội dung đ ộng. Một trang ASP thực ch ất là m ột file HTML có nhúng các khối server-side VBScript hay JavaScript. Khi một trình duy ệt khách yêu c ầu một trang ASP page, web server sẽ sinh ra mã HTML, xử lí các server-side script khi chúng đến. Thường thì các script s ẽ truy c ập vào một c ơ s ở d ữ liệu để lấy dữ liệu, và biểu diễn trên trang HTML. ASP là cách đơn giản nhất để tạo các ứng dụng browser-based. ASP tất nhiên cũng có một vài hạn chế. Trước tiên, các trang ASP thỉnh thoảng tr ở nên r ất ch ậm b ởi vì mã server-side đ ược thông dịch thay vì đựơc biên dịch. Thứ hai, các file ASP khó bảo trì bởi vì chúng không có c ấu trúc; mã server-side ASP và HTML được trộn lẫn với nhau. Thứ ba, ASP đôi khi kho phát triển bởi nó không quan tâm đến bẫy l ỗi và ki ểm tra ki ểu. Cụ thể, nếu bạn dùng VBScript và muốn bẫy lỗi trên các trang của bạn, bạn phải dung câu l ệnh On Error Resume Next, và cho phép tất cả các thành phần gọi thông qua một Err.Number để chắc rằng tất cả đều tốt. ASP.NET là một phiên bản mới của ASP đã cải tiến rất nhiều các thiếu xót của nó. Nó không chỉ thay thế ASP; hơn thế, các trang ASP.NET có thể sống chung với các ứng dụng ASP trên cùng một máy chủ. Tất nhiên bạn có thể l ập trình ASP.NET với C#! Mặt dù các chương (14-16) sẽ bàn kĩ về ASP.NET, nhưng chúng ta cũng nói qua một vài đ ặc tính quan tr ọng c ủa nó.
  14. Các đặc tính của ASP.NET Trước tiên, và có lẽ là quan trọng nhất, các trang ASP.NET là các trang có cấu trúc. Có nghĩa là mỗi trang là th ực t ế là m ột lớp được thừa kế từ lớp .NET System.Web.UI.Page, và có thể ghi đè một tập các phương thức sẽ dùng trong thời gian sống của trang web (bạn hãy tưởng tượng rằng nhữn sự kiện này như là anh em bà con với các s ự ki ện OnApplication_Start và OnSession_Start trong file global.asa của ASP cũ.) Bởi vì bạn có thể chuyển các thao tác của một trang thành các s ự ki ện sáng nghĩa hơn, chính vì thể mà các tramg ASP.NET dễ hiểu hơn. Một điểm mạnh khác là các trang ASP.NET có thể được tạo trong VS.NET, cùng chung môi tr ường với các thành ph ần lu ận lí và dữ liệu sẽ được dùng trong các trang web này. Một nhóm đề án VS.NET, hoặc solution, chứa tất cả các file liên quan đển một ứng dụng. Hơn thế nữa bạn có thể bẫy lỗi các trang ASP của bạn ngay trong trình thi ết k ế; tr ước đây, th ật là khó khăn để có thể cấu hình InterDev và các đề án web server để thực hi ện bẫy l ỗi. Rõ ràng, đặc tính ASP.NET's code-behind giúp các bạn có thể dễ dàng cấu trúc một trang web. ASP.NET cho phép bạn tách biệt các chức năng server-side của trang thành một lớp, biên dịch lớp đó thành một DLL, và đ ặt DLL đó vào một th ư mục bên dưới phần HTML. Một code-behind chi phối đỉnh của một trang web tương đương với file DLL của nó. Khi một trình duyệt yêu cầu trang, web server phát ra các sự kiện trong lớp của page's code-behind DLL. Cuối cùng không kém phần quan trọng, ASP.NET thật sự đáng chú ý với khả năng tăng cường s ự thực thi. Ng ược l ại v ới các trang ASP được thông dịch cho mỗi yêu cầu, web server lưu giữ lại các trang ASP.NET sau quá trình biên d ịch. Nghĩa là các yêu cầu sau của một trang ASP.NET sẽ thực thi nhanh hơn trang đầu tiên. ASP.NET dễ tạo các trang hơn bởi vì nó được chiếu bởi trình duyệt, bạnc có thể s ử dụng một môi tr ường mạng intranet. Theo kinh nghiệm truyền thống thì một ứng dụng form-based thường là tốt hơn một user interface, nhưng cũng khó b ảo trì hơn vì nó chạy trên nhiều máy khác nhau. Với sự ra đời của Internet Explorer 5 và sự thực thi mơ hồ của Navigator 6, t ất nhiên các đ ặc tính c ủa ứng d ụng form-based bị che mờ. IE 5's hỗ trợ nhất quán và mạnh mẽconsistent cho DHTML cho phép các nhà l ập trình t ạo các ứng d ụng web-based đẹp là lớn hơn. Tất nhiên, các ứng dụng này bắt buộc phải theo chuẩn của IE và không đ ược hỗ tr ợ bởi Navigator. Trong nhiều lĩnh vực công nghiệp, chuẩn này đã trở nên phổ biến. Web Forms Để dễ dàng cho việc tạo các trang có cấu truc, Visual Studio .NET cung cấp Web Forms. Chúng cho phép bạn tạo các trang ASP.NET sinh động như cách mà VB 6 hay C++ Builder windows đã làm; nó cách khác, bằng cách kéo các controls t ừ toolbox vào form, sau đó sắp xếp cho đẹp, điền mã quản lí sự kiện thích hợp vào control đó. Khi bạn dung C# đ ể t ạo các Web Form, bạn đang tạo một lớp C# được thừa kế từ lớp Page base, và một trang ASP được chỉ định như là code-behind. Tất nhiên, không bắt buộc phải dùng C# để tạo một Web Form; bạn có thể dùng VB.NET hoặc một ngôn ngữ biết .NET khác. In the past, the difficulty of web development has discouraged some teams from attempting it. To succeed in web development, you had to know so many different technologies, such as VBScript, ASP, DHTML, JavaScript, and so on. By applying the Form concepts to web pages, Web Forms promise to make web development easier. Only time will tell, however, how successful Web Forms and Web Controls (which we'll look at next) will be at insulating the developer from the complexities of web design. Web Controls Các control thường được cư trú trên một Web Form không phải là các ActiveX control. H ơn nữa, chúng là XML tags trong ASP namespace và browser có thể chuyển sang HTML và client-side script khi một trang đ ược yêu c ầu. Đ ặc bi ệt h ơn, web server có thể các điều khiển server-side control theo nhi ều cách khác nhau, sinh ra s ự bi ến đ ổi phù h ợp v ới các yêu c ầu c ủa các web browser riêng biệt. Điều này có nghĩa là sẽ dễ dàng viết các giao di ện ng ười dùng tinh vi cho các trang web, đ ừng bận tâm đến vấn đề tương thích trình duyệt web– bởi vì Web Forms sẽ làm đi ều đó cho bạn. Bạnc có thể dùng C# hay VB.NET để mở rộng hộp công cụ Web Form. Việc tạo một server-side control mới đ ơn gi ản là thực thi lớp .NET System.Web.UI.WebControls.WebControl. Web Services Ngày nay, các trang HTML là nguyên nhân của hầu hết các xung đ ột trên World Wide Web. V ới XML, các máy vi tính có m ột định dạng device-independent để dùng cho việc truyền thông với các máy khác trên mạng Web. Trong t ương l ại, các máy tính có thể sẽ dùng Web và XML để trao đổi thông tin hơn là dùng các line chuyên dụng và theo nh ững đ ịnh d ạng riêng nh ư EDI (Electronic Data Interchange). Các Web Service được thiết kế cho một web hướng dịch vụ, trong đó các máy tính ở xa cung cấp cho nhau các thông tin động có thể phân tích và tái định dạng, tr ước khi trao l ại cho ng ười dùng. M ột Web Service là cách đơn giản nhất để một máy tính có thể cung cấp thông tin cho các máy tính khác trên Web dưới đ ịnh d ạng XML. Về mặt kĩ thuật, một Web Service trong .NET là một trang ASP.NET theo đ ịnh dạng XML thay vì theo đ ịnh d ạng HTML đ ể yêu cầu các client. Các trang này có một code-behind DLL chứa một lớp xuất phát từ lớp WebService. VS.NET IDE cung cấp một cơ chế để tiện cho việc phát triển Web Service.
  15. Có hai lí do chính để một tổ chức chọn Web Services. Lí do thứ nhất là bởi vì chúng đáng tin c ậy trên HTTP, Web Services có thể dùng các mạng có sẵn (the Web) như một môi trường cho việc truyền thông. Một lí do khác là bởi vì các Web Service dùng XML, một định dạng dữ liệu tự mô tả, mang tính phổ biến, và độc lập nền. Tạo các Windows Form Mặc dù C# và .NET được thiết kế để phát triển web, nhưng chúng vẫn hỗ trợ mạnh mẽ cho cái g ọi là ứng dụng "fat client", các ứng dụng có thể được cài đặt trên một máy người dùng cuối. Hỗ trợ này g ọi là Windows Forms. Một Windows Form là câu trả lời của .NET cho VB 6 Form. Dùng để thi ết k ế một giao diên window sinh đ ộng, b ạn ch ỉ đ ơn giản kéo các control từ vào trên Windows Form. Để xác định cách xử của window, bạn vi ết các thủ t ục qu ản lí s ự ki ện cho form controls. Một đề án Windows Form được dịch thành một EXE phải đ ược cài đ ặt trong một môi tr ường ở máy tính người dùng cuối. Giống như các kiểu đề án .NET khác, đề án Windows Form được hỗ tr ợ cho cả VB.NET và C#. Chúng ta sẽ nói kĩ về Windows Forms trong chương 7. Windows Controls Mặc dù Web Forms và Windows Forms được phát triển theo cùng một cách, bạn dùng các loại khác nhau c ủa controls đ ể đ ịnh vị chúng. Web Forms dùng Web Controls, và Windows Forms dùng Windows Controls. Một Windows Control là một ActiveX control. Đằng sau sự thực thi của một Window control, là s ự biên dich sang m ột DLL để có thể cài đặt trên máy khách. Thật vậy, .NET SDK cung cấp một tiện ích dùng để t ạo một vỏ bọc cho các ActiveX control, vì thể chúng có thể được đặt trong Windows Forms. Giống trường hợp này các Web Control, Windows Control đ ược tạo thành từ một lớp khác System.Windows.Forms.Control. Windows Services Một Windows Service là một chương trình được thiết kế để chạy trên nền Windows NT/2000/XP (không hỗ tr ợ trên Windows 9x). Các dịch vụ này rất hữu ích khi bạn muốn một chương trình có thể chạy liên t ục và s ẵn sàng đáp ứng các s ự kiện mà không cần người dùng phải khởi động. Ví dụ như một World Wide Web Service ở trên các web server luôn l ắng nghe các yêu cầu từ trình khách. Thật dễ dàng để viết các dịch vụ trong C#. Với thư viện lớp cơ sở .NET Framework sẵn có trong không gian tên System.ServiceProcess namespace chuyên dùng để tổ chức các tác vụ boilerplate kết hợp với các dịch vụ, ngoài ra, Visual Studio .NET cho phép bạn tạo một đề án C# Windows Service, với các mã nguồn cơ bản ban đ ầu. Chúng ta s ẽ khám cách viết một C# Windows Services trong chương 22. Tóm tắt Chúng ta đã khảo sát nhiều vấn đề trong chương này, chúng ta sẽ tóm lại các vấn đ ề quan tr ọng trong .NET Framework và mối quan hệ của nó với C#. Chúng tôi đã trình bày cách mà tất cả các ngôn ng ữ hướng .NET đ ược biên d ịch thành Intermediate Language trước khi được biên dịch và thực thi bởi Common Language Runtime. Chúng tôi cũng đã trình bày vai trò của các đặc tính sau trong .NET trong quá trình biên dịch và thực thi: • Các Assembly và thư viện lớp cơ sở của .NET • Các thành phần COM • Quá trình biên dịch JIT • Các Application domain • Garbage Collection Lưu đồi sau cho ta một cái nhìn về vài trò của các đặc tính này trong quá trình biên d ịch và th ực thi:
  16. Chúng tôi cũng đã trình bày những đặc trưng của IL, cụ thể là định nghĩa ki ểu mạnh và hướng đ ối t ượng. Chúng tôi đã chú thích các đặc tính này ảnh hưởng đến các các ngôn ngữ hướng .NET khác, bao g ồm C#. Chúng tôi cũng đã chú thich cách mà định nghĩ kiểu mạnh có thể hỗ trợ tương hoạt ngôn ngữ chéo, cũng như các dịch vụ CLR chẳng hạn như trình thu gom rác và bảo mật. Ở phần cuối của chương tôi đã nói về cách tạo các ứng dụng C# dựa trên các công ngh ệ của .NET trong đó có ASP.NET. Giờ đây chúng ta đã có cái nền, chương tới sẽ chỉ ra cách viết mã trong C#. Chương 2: Cơ bản C# Tổng quan : Trong chương này chúng tôi sẽ cung cấp cho bạn những kiến thức cơ bản nh ất của ngôn ng ữ l ập trình C#. Nh ững ch ủ đ ề chính chúng ta sẽ được học sau đây : • Khai báo biến • Khởi tạo và phạm vi hoạt động của biến • C#'s predefined data types • Cách sử dụng các vòng lặp và câu lệnh. • Gọi và hiển thị lớp và phương thức • Cách sử dụng mảng • Toán tử • An toàn kiểu và cách để chuyển các kiểu dữ liệu • Enumerations • Namespaces • Phương thức của hàm Main( ) • Cơ bản trình biên dịch dòng lệnh trong C# • Using System.Console để thực hiện I/O • Sử dụng chú thích trong C# và Visual Studio . NET • Các định danh và từ khoá trong C# Cuối chương này bạn sẽ có đủ khả năng viết một chương trình đơn giản bằng C# mà bạn không cần phải bi ết s ự k ế thừa hay hướng đối tượng mà chúng tôi sẽ trình bày những phần này ở vài chương tới của quyển sách.
  17. This document is created from a CHM file automatically by an unregistered copy of CHM-2- Word. The content of this chapter is skipped, please register CHM-2-Word to get full features. For registration information, please refer to: http://www.macrobject.com Chương trình đầu tiên ! Chúng ta sẽ bắt đầu theo cách truyền thống là tạo một chương trình vi ết bằng C# r ồi cho biên d ịch và ch ạy th ử nghi ệm. Việc phân tích chương trình con này sẽ dẫn dắt bạn vào những chức năng chủ chốt của ngôn ng ữ C#. Bạn có thể biên dịch chương trình này bằng cách khỏ vào chương trình soạn thảo văn bản đ ơn gi ản, Notepad ch ẳng h ạn, rồi cho cất trữ dưới dạng tập tin với tên mở rộng là .cs (tắt chữ C sharp), rồi cho chạy trình biên dịch C# command_line (scs.exe) ví dụ tập tin First.cs : using System; namespace Wrox.ProCSharp.Basics { class MyFirstCSharpClass { static void Main() { Console.WriteLine("This isn't at all like Java!"); Console.ReadLine(); return; } } } Một chương trình khả thi mang tên First.exe sẽ được tạo ra, và bạn có thể cho chạy chương trình này t ừ command line giống như với DOS hoặc từ Windows Explorer như bất cứ chương trình khả thi nào.Chạy chương trình như sau : csc First.cs Microsoft (R) Visual C# .NET Compiler version 7.00.9466 for Microsoft (R) .NET Framework version 1.0.3705 Copyright (C) Microsoft Corporation 2001. All rights reserved. First This isn't at all like Java! Download First Nhưng trước tiên bạn nên biết trên C# cũng như trên các ngôn ngữ C khác chương trình đ ược c ấu thành b ởi câu l ệnh (statement ) và câu lệnh C# được kết thúc bởi một dấu chấm phẩy (;).Nhi ều câu l ệnh có thể g ộp thành một kh ối đ ược bao ở hai đầu bởi cặp dấu ngoặc nghéo {}, câu lệnh nếu dài có thể tiếp tục xuống hàng dưới không cần đ ến một ký t ự báo cho biết câu lệnh tiếp tục hàng dưới. Biến và Hằng Một biến dùng để lưu trữ giá trị mang một kiểu dữ liệu nào đó. Cú pháp C# sau đây để khai báo một biến : [ modifier ] datatype identifer ; Với modifier là một trong những từ khoá : public, private, protected, . . . còn datatype là ki ểu d ữ li ệu (int , long , float. . . ) và identifier là tên biến.
  18. Thí dụ dưới đây một biến mang tên i kiểu số nguyên int và có thể được truy cập bởi bất cứ hàm nào. thí dụ : public int i ; Ta có thể gán cho biến một giá trị bằng toán tử "=". i = 10 ; Ta cũng có thể khai báo biến và khởi tạo cho biến một giá trị như sau : int i = 10 ; Nếu ta khai báo nhiều biến có cùng kiểu dữ liệu sẽ có dạng như sau: int x = 10; y = 20; int x = 10; bool y = true ; // khai báo trên đúng int x = 10 , bool = true // khai báo trên có lỗi Phạm vi hoạt động của biến (Variable Scope). Phạm vi hoạt động của biến là vùng đoạn mã mà từ đấy biến có thể được truy xuất. Trong một phạm vi hoạt động (scope), không thể có hai biến cùng mang một tên trùng nhau. Thí dụ ta không thể làm như sau : int x = 20; // một số câu lệnh ở đây int x = 30; Xét ví dụ sau : using System; namespace Wrox.ProCSharp.Basics { public class ScopeTest { public static int Main() { for (int i = 0; i < 10; i++) { Console.WriteLine(i); } // biến i ra khỏi phạm vi // Chúng ta có thể khai báo thêm biến i ở đây for (int i = 9; i >= 0; i--) { Console.WriteLine(i); } // biến i ra khỏi phạm vi ở đây return 0; } } } Download ScopeTest Đoạn mã trên đơn giản in ra các số từ 0 đến 9, rồi lộn ngược lại từ 9 đến 0, sử dụng vòng l ặp for.Chúng ta s ẽ đ ề cập loại vòng lặp này. Điều quan trọng là ở đây chúng ta khai báo biến i hai l ần trong cùng một hàm ScopeTest.Chúng ta có th ể làm được điều này vì i được khai báo trong vòng lặp nghĩa là biến i cục bộ đ ối với vòng l ặp.Một khi vòng l ặp hoàn thành nhiệm vụ thì biến thoát khỏi phạm vi, và không thể truy xuất được nữa. Chúng ta xem tiếp một ví dụ khác : public static int Main() { int j = 20; for (int i = 0; i < 10; i++) { int j = 30; // không thể thực thi - j vẫn còn trong phạm vi Console.WriteLine(j + i); } return 0; } Đoạn mã trên sẽ được biên dịch mặc dù có hai biến đặc tên j trong ph ạm vi không có ph ương thức hàm main( ) bi ến j được định nghĩa ở lớp mức và không đi ra ngoài đến khi lớp bị huỷ ( trong trường hợp này chương trình kết thúc khi hàm main( ) kết thúc), biến j được định nghĩa trong hàm main( ) phương thức ẩn trong l ớp mức với bi ến cùng tên j nên khi ch ạy chương trình sẽ hiện giá trị 30.
  19. Ta xem đoạn thí dụ sau : using System; namespace Wrox.ProCSharp.Basics { class ScopeTest2 { static int j = 20; public static void Main() { int j = 30; Console.WriteLine(j); return; } } } Chương trình vẫn hoạt động và cho kết quả là 30. Download ScopeTest2 HẰNG: Một hằng (constant) là một biến nhưng trị không thể thay đổi được suốt thời gian thi hành chương trình. Đôi lúc ta cũng cần có những giá trị bao giờ cũng bất biến. Thí dụ const int a = 100; // giá trị này không thể bị thay đổi Trong định nghĩa lớp mà ta sẽ xem sau, người ta thường định nghĩa những mục tin (field) đ ược g ọi là read-only variable, nghĩa là những biến chỉ được đọc mà thôi Hằng có những đặc điểm sau : • Hằng bắt buộc phải được gán giá trị lúc khai báo.Một khi đã được khởi gán thì không thể vi ết đè chồng lên. • Trị của hằng phải có thể được tính toán vào lúc biên dịch, Do đó không thể gán một hằng t ừ một tr ị của một bi ến. Nếu muốn làm thế thì phải sử dụng đến một read-only field. • Hằng bao giờ cũng static, tuy nhiên ta không thể đưa từ khoá static vào khi khai báo hằng. Có ba thuận lợi khi sử dụng hằng trong chương trình của bạn : • Hằng làm cho chương trình đọc dễ dàng hơn, bằng cách thay thế những con s ố vô cảm bởi những tên mang đ ầy ý nghĩa hơn. • Hằng làm cho dễ sữa chương trình hơn. • Hằng làm cho việc tránh lỗi dễ dàng hơn, nếu bạn gán một trị khác cho một hằng đâu đó trong chương trình sau khi bạn đã gán giá trị cho hằng, thì trình biên dịch sẽ thông báo sai lầm. Câu lệnh điều kiện Câu lệnh điều kiện Câu lệnh điều kiện if : Cú pháp như sau: if (condition) statement(s) [else statement(s)] Xét ví dụ sau: Nếu có nhiều hơn một câu lệnh để thi hành trong câu điều kiện chúng ta sẽ đưa t ất cả các câu l ệnh này vào trong d ấu ngoặc móc ({ ... }) giống như ví dụ dưới đây bool isZero; if (i == 0) { isZero = true;
  20. Console.WriteLine("i is Zero"); } else { isZero = false; Console.WriteLine("i is Non-zero"); } Đoạn code trên kiểm tra isZero có bằng 0 hay không. Xét ví dụ: Trong ví dụ dưới đây chúng ta dùng câu điều kiện íf . . . else để kiểm tra nhi ều đi ều ki ện . using System; namespace Wrox.ProCSharp.Basics { class MainEntryPoint { static void Main(string[] args) { Console.WriteLine("Type in a string"); string input; input = Console.ReadLine(); if (input == "") { Console.WriteLine("You typed in an empty string"); } else if (input.Length < 5) { Console.WriteLine("The string had less than 5 characters"); } else if (input.Length < 10) { Console.WriteLine("The string had at least 5 but less than 10 characters"); } Console.WriteLine("The string was " + input); } } } Download Conditional Đoạn code trên không giới hạn bao nhiêu else if's trong câu điều kiện if (i == 0) Console.WriteLine("i is Zero"); // câu lệnh chỉ thi hành khi i == 0 Console.WriteLine("i can be anything"); // câu lệnh thi hành bất kì giá trị của i Câu lệnh switch Các câu lệnh if nằm lồng rất khó đọc, khó gỡ rối. Khi bạn có một loạt lựa chọn ph ức t ạp thì nên s ử dụng câu l ệnh switch. Cú pháp như sau: switch (biểu thức) { casce biểu thức ràng buộc: câu lệnh câu lệnh nhảy [default: câu lệnh mặc định] } Thí dụ sau: Thí dụ sẽ kiểm tra integerA thoả đúng trong các trường hợp 1, 2, 3 không nếu không đúng s ẽ th ực thi tr ường h ợp default switch (integerA) { case 1:
Đồng bộ tài khoản