Sách Giải pháp lập trình C# & .NET - Tác giả Nguyễn Ngọc Bình Phương

Chuyên khảo phân tích Giải pháp lập trình, đánh giá các khía cạnh quan trọng, đề xuất hướng nghiên cứu tiếp theo., phục vụ nghiên cứu và ứng dụng thực tiễn

Người đăng

Ẩn danh
706
3
0

Phí lưu trữ

135 Point

Tóm tắt

I. Khám phá 5 giải pháp lập trình C nền tảng cho

Trong lĩnh vực phát triển phần mềm, việc tìm kiếm giải pháp lập trình hiệu quả cho các vấn đề thường gặp là yếu tố then chốt. Tài liệu "Các giải pháp lập trình C#" khảo sát chiều rộng của thư viện lớp .NET Framework, cung cấp các phương pháp tiếp cận cụ thể, ngắn gọn. Mỗi giải pháp không nhằm mục đích hướng dẫn lập trình C# từ đầu, mà đóng vai trò như một tài nguyên tham khảo giá trị. Ngay cả những người mới làm quen với lập trình ứng dụng trên nền tảng .NET Framework cũng có thể tìm thấy hướng đi đúng đắn. Lý tưởng nhất, khi đối mặt với một thách thức, tài liệu này sẽ cung cấp một giải pháp hoàn chỉnh hoặc ít nhất là gợi ý một con đường phù hợp. Trọng tâm của phương pháp này là học hỏi thông qua thực hành. Việc chỉ đọc về các lớp trong thư viện .NET là không đủ để trở nên thành thạo. Lập trình viên phải sử dụng, thử nghiệm và viết nhiều chương trình để thực sự hiểu rõ. Các ví dụ và mã lệnh trong tài liệu cung cấp một điểm khởi đầu hoàn hảo, tạo bàn đạp cho quá trình thử nghiệm của mỗi cá nhân. Cấu trúc và nội dung thực tiễn của các giải pháp giúp mở rộng kiến thức một cách hệ thống, từ phát triển ứng dụng cơ bản, thao tác dữ liệu, cho đến các chủ đề nâng cao như lập trình mạng, bảo mật và mật mã. Cách tiếp cận này nhấn mạnh rằng giải pháp lập trình không chỉ là viết mã lệnh, mà còn là việc hiểu và áp dụng đúng các công cụ có sẵn trong một hệ sinh thái lớn như .NET Framework. Tài liệu gốc được xây dựng dựa trên phiên bản .NET Framework 1.1, tuy nhiên nhiều khái niệm và giải pháp vẫn giữ nguyên giá trị cốt lõi trong các phiên bản hiện đại hơn. Sự thành công trong lập trình đòi hỏi sự kết hợp giữa lý thuyết vững chắc và kinh nghiệm thực tiễn, và việc phân tích các giải pháp có sẵn là một con đường hiệu quả để đạt được điều đó.

1.1. Tiếp cận vấn đề theo mô hình Vấn đề Giải pháp

Mỗi giải pháp lập trình được trình bày theo một cấu trúc thống nhất và hiệu quả: "vấn đề/giải pháp". Phương pháp này đi thẳng vào trọng tâm, giúp người đọc nhanh chóng xác định thách thức và tìm thấy câu trả lời tương ứng. Thay vì trình bày lý thuyết dài dòng, cách tiếp cận này cung cấp các đoạn mã ví dụ cụ thể, minh họa trực tiếp cho giải pháp. Trích dẫn từ tài liệu gốc: "Mỗi giải pháp được trình bày theo dạng “vấn đề/giải pháp” một cách ngắn gọn và kèm theo là các ví dụ mẫu." Điều này đặc biệt hữu ích cho các lập trình viên đang làm việc trong các dự án thực tế, nơi thời gian là yếu tố quan trọng. Mô hình này không chỉ cung cấp câu trả lời mà còn khuyến khích tư duy giải quyết vấn đề, một kỹ năng thiết yếu cho bất kỳ nhà phát triển phần mềm nào.

1.2. Vai trò của thư viện lớp .NET Framework trong lập trình

Để trở thành một lập trình viên C# thành thạo, việc hiểu sâu về thư viện lớp .NET Framework là không thể thiếu. Thư viện này là một tập hợp khổng lồ các lớp, giao diện và kiểu giá trị, cung cấp các chức năng đã được xây dựng sẵn cho nhiều tác vụ lập trình. Từ việc thao tác với chuỗi, xử lý file, kết nối cơ sở dữ liệu cho đến xây dựng giao diện người dùng đồ họa (GUI), thư viện này đều có các công cụ hỗ trợ. Việc tận dụng hiệu quả thư viện lớp .NET giúp giảm đáng kể thời gian phát triển, tránh "phát minh lại bánh xe" và đảm bảo mã lệnh tuân thủ các tiêu chuẩn chung. Các giải pháp lập trình được giới thiệu chủ yếu xoay quanh việc khai thác sức mạnh của thư viện này, biến nó thành một nguồn tài nguyên vô giá cho các nhà phát triển.

II. Thách thức thường gặp khi phát triển ứng dụng

Quá trình phát triển một ứng dụng C# trên nền tảng .NET Framework luôn đi kèm với những thách thức cố hữu đòi hỏi các giải pháp lập trình phù hợp. Một trong những quyết định đầu tiên và quan trọng nhất là lựa chọn loại hình ứng dụng. Việc xây dựng một ứng dụng Console không có giao diện đồ họa hoàn toàn khác biệt so với một ứng dụng Windows Form với giao diện người dùng phức tạp. Lựa chọn sai có thể dẫn đến việc phải cấu trúc lại toàn bộ dự án sau này. Một thách thức lớn khác là quản lý và tái sử dụng mã lệnh. Khi dự án phát triển, việc duy trì một khối mã nguồn nguyên khối (monolithic) trở nên cồng kềnh và khó bảo trì. Nhu cầu phân tách mã lệnh thành các thành phần độc lập, có thể tái sử dụng như modulethư viện là rất cấp thiết. Điều này không chỉ giúp mã nguồn gọn gàng hơn mà còn tối ưu hóa hiệu suất bằng cách chỉ nạp các thành phần cần thiết vào bộ nhớ. Cuối cùng, vấn đề bảo mật và toàn vẹn của ứng dụng là một mối quan tâm hàng đầu. Làm thế nào để đảm bảo rằng một assembly (đơn vị triển khai của .NET) không bị sửa đổi sau khi phát hành? Làm sao để cung cấp cho nó một định danh duy nhất và đáng tin cậy? Những câu hỏi này dẫn đến sự ra đời của các kỹ thuật như tạo tên mạnh (strong name), một cơ chế sử dụng mã hóa khóa công khai để ký và xác minh các assembly. Việc giải quyết thành công những thách thức này là nền tảng để xây dựng các ứng dụng mạnh mẽ, hiệu quả và an toàn. Mỗi giải pháp lập trình được đưa ra đều nhằm mục tiêu xử lý một hoặc nhiều khía cạnh của các vấn đề cốt lõi này.

2.1. Lựa chọn giữa ứng dụng Console và ứng dụng GUI

Việc quyết định xây dựng một ứng dụng Console hay một ứng dụng Windows Form (GUI) phụ thuộc hoàn toàn vào mục đích sử dụng. Ứng dụng Console không cần giao diện người dùng đồ họa, hoạt động chủ yếu thông qua dòng lệnh. Loại ứng dụng này phù hợp cho các tác vụ tự động, xử lý hàng loạt, hoặc các công cụ dành cho nhà phát triển. Ngược lại, ứng dụng GUI cung cấp một giao diện trực quan, cho phép người dùng tương tác thông qua các điều khiển như nút bấm, hộp văn bản. Đây là lựa chọn bắt buộc cho hầu hết các ứng dụng dành cho người dùng cuối. Việc triển khai phương thức Main và sử dụng các lệnh biên dịch (/target:exe cho Console và /target:winexe cho GUI) là khác nhau, đòi hỏi một định hướng rõ ràng ngay từ đầu.

2.2. Bài toán tái sử dụng mã lệnh với Module và Thư viện

Khi các dự án phần mềm lớn dần, việc sao chép và dán mã lệnh giữa các phần khác nhau là một thói quen xấu, dẫn đến khó khăn trong việc bảo trì và cập nhật. Giải pháp lập trình cho vấn đề này là cấu trúc mã nguồn thành các modulethư viện (.dll). Một module là một đơn vị biên dịch chứa mã MSIL và siêu dữ liệu, có thể được liên kết để tạo thành một assembly. Một thư viện là một assembly hoàn chỉnh được thiết kế để chia sẻ chức năng cho nhiều ứng dụng khác nhau. Việc sử dụng các thành phần này giúp tăng hiệu quả thực thi, giảm sử dụng bộ nhớ và thúc đẩy khả năng liên tác giữa các ngôn ngữ lập trình khác nhau trên nền tảng .NET.

2.3. Đảm bảo tính toàn vẹn và định danh cho Assembly

Một trong những rủi ro lớn nhất đối với phần mềm phân phối là nguy cơ bị giả mạo hoặc sửa đổi trái phép. Một assembly không được bảo vệ có thể bị dịch ngược, thay đổi mã lệnh và phát hành lại dưới danh nghĩa của nhà phát triển gốc. Để giải quyết vấn đề này, .NET Framework cung cấp một giải pháp lập trình mạnh mẽ là tên mạnh (strong name). Bằng cách sử dụng một cặp khóa công khai/riêng tư để ký vào assembly, một định danh duy nhất và không thể giả mạo được tạo ra. Bất kỳ thay đổi nào đối với assembly sau khi ký sẽ làm cho chữ ký số không hợp lệ, giúp hệ thống và người dùng xác minh được tính nguyên bản của mã lệnh.

III. Hướng dẫn xây dựng các loại ứng dụng C cơ bản nhất

Việc xây dựng một ứng dụng C# bắt đầu bằng việc lựa chọn đúng loại dự án và cấu trúc mã nguồn phù hợp. Hai dạng ứng dụng cơ bản nhất là ứng dụng Consoleứng dụng Windows Form. Đối với ứng dụng Console, điểm khởi đầu là một phương thức tĩnh Main. Đây là nơi mã lệnh bắt đầu thực thi. Trình biên dịch C# (csc.exe) mặc định sẽ tạo ra một ứng dụng Console nếu không có chỉ định nào khác. Lệnh biên dịch điển hình là csc /target:exe YourFile.cs. Khi ứng dụng có nhiều file mã nguồn, cần chỉ định tất cả chúng, đồng thời có thể dùng cờ /out để đặt tên file thực thi và /main để chỉ rõ lớp chứa điểm nhập nếu có nhiều phương thức Main. Mặt khác, việc xây dựng một ứng dụng dựa-trên-Windows yêu cầu một cách tiếp cận khác. Mặc dù vẫn cần một phương thức Main tĩnh, nhiệm vụ chính của nó là khởi tạo và chạy form chính của ứng dụng. Cần tạo một lớp kế thừa từ System.Windows.Forms.Form và truyền một thể hiện của nó vào phương thức Application.Run(). Lệnh biên dịch cho loại ứng dụng này là csc /target:winexe YourForm.cs. Việc sử dụng winexe thay vì exe đảm bảo rằng không có cửa sổ console nào xuất hiện khi ứng dụng chạy, mang lại trải nghiệm người dùng tốt hơn. Trong cả hai trường hợp, việc hiểu rõ các đối số của trình biên dịch và cấu trúc phương thức Main là kiến thức nền tảng, là giải pháp lập trình đầu tiên mà mọi nhà phát triển C# cần nắm vững để biến mã nguồn thành một chương trình thực thi được.

3.1. Phương pháp tạo ứng dụng Console từ dòng lệnh

Để tạo một ứng dụng Console, cần hiện thực một phương thức public static void Main() trong ít nhất một lớp. Phương thức này là điểm nhập của chương trình. Ví dụ, lớp HelloWorld có thể chứa một phương thức Main để in ra dòng chữ "Hello, world". Quá trình biên dịch được thực hiện bằng trình biên dịch C# (csc.exe). Lệnh cơ bản là csc HelloWorld.cs. Nếu có nhiều file mã nguồn, ví dụ ConsoleUtils.csHelloWorld.cs, và cả hai đều có phương thức Main, phải chỉ định rõ điểm nhập. Lệnh biên dịch sẽ là: csc /out:MyApp.exe /main:HelloWorld ConsoleUtils.cs HelloWorld.cs. Đối số /out chỉ định tên file thực thi, và /main xác định lớp chứa điểm nhập chính.

3.2. Quy trình tạo ứng dụng Windows Form GUI cơ bản

Một ứng dụng Windows Form cung cấp giao diện người dùng đồ họa. Để xây dựng nó, cần thực hiện các bước sau: tạo một lớp kế thừa từ System.Windows.Forms.Form, khai báo các điều khiển (controls) như Button, TextBox, và viết các phương thức xử lý sự kiện cho chúng. Trong phương thức khởi dựng của form, các điều khiển này được tạo và cấu hình. Cuối cùng, một phương thức public static void Main() sẽ tạo một thể hiện của lớp form và gọi Application.Run(new MyForm()) để hiển thị form và bắt đầu vòng lặp thông điệp. Để biên dịch, sử dụng lệnh csc /target:winexe /reference:System.Windows.Forms.dll MyForm.cs. Cờ /target:winexe rất quan trọng để ngăn cửa sổ console không cần thiết xuất hiện khi ứng dụng chạy.

IV. Bí quyết quản lý mã lệnh hiệu quả với module và thư viện

Quản lý mã lệnh hiệu quả là một trong những giải pháp lập trình quan trọng nhất để xây dựng các ứng dụng lớn và dễ bảo trì. Thay vì biên dịch toàn bộ mã nguồn vào một file thực thi duy nhất, .NET Framework cho phép phân tách mã thành các đơn vị nhỏ hơn gọi là modulethư viện. Một module là khối xây dựng cơ bản của một assembly. Nó chứa mã ngôn ngữ trung gian (MSIL), siêu dữ liệu (metadata) và các tài nguyên. Việc biên dịch mã nguồn thành module (sử dụng cờ /target:module) mang lại nhiều lợi ích. Thứ nhất, nó giúp tối ưu hóa hiệu suất, vì bộ thực thi sẽ chỉ nạp một module vào bộ nhớ khi các kiểu định nghĩa trong đó thực sự được yêu cầu. Điều này đặc biệt hữu ích cho các ứng dụng lớn có những chức năng ít được sử dụng. Thứ hai, module là cầu nối cho khả năng tương tác ngôn ngữ. Mã nguồn viết bằng các ngôn ngữ .NET khác nhau (như VB.NET) có thể được biên dịch thành các module riêng biệt, sau đó được liên kết lại thành một assembly duy nhất bằng trình biên dịch C# (sử dụng cờ /addmodule). Một khái niệm liên quan nhưng ở cấp độ cao hơn là thư viện (library). Thư viện, thường có phần mở rộng .dll, là một assembly hoàn chỉnh chứa các chức năng có thể được chia sẻ và tái sử dụng bởi nhiều ứng dụng. Việc tạo thư viện (sử dụng cờ /target:library) cho phép đóng gói các lớp và phương thức tiện ích. Các ứng dụng khác sau đó có thể tham chiếu đến thư viện này (sử dụng cờ /reference) để sử dụng các chức năng đó mà không cần phải có mã nguồn gốc. Việc áp dụng các giải pháp lập trình này giúp tạo ra các hệ thống linh hoạt, hiệu quả và dễ dàng mở rộng.

4.1. Cách tạo và sử dụng Module để tối ưu ứng dụng

Một module là một file trung gian không thể thực thi độc lập, chứa mã MSILsiêu dữ liệu. Để tạo một module từ file Utils.cs, sử dụng lệnh: csc /target:module Utils.cs. Lệnh này sẽ tạo ra file Utils.netmodule. Lợi ích chính của module là cho phép nạp các phần của ứng dụng theo yêu cầu (just-in-time), giúp giảm thời gian khởi động và tiết kiệm bộ nhớ. Nhiều module sau đó có thể được kết hợp để tạo thành một assembly đa file. Ví dụ, để xây dựng ứng dụng MyApp.exe từ file Main.cs và module Utils.netmodule, sử dụng lệnh: csc /out:MyApp.exe /addmodule:Utils.netmodule Main.cs. Ứng dụng MyApp.exe sẽ chứa manifest của assembly và phụ thuộc vào file Utils.netmodule khi chạy.

4.2. Xây dựng và tham chiếu Thư viện .dll để tái sử dụng

Một thư viện (.dll) là một assembly có thể tái sử dụng, chứa các lớp và phương thức mà các ứng dụng khác có thể gọi. Để xây dựng file MyLibrary.dll từ các file mã nguồn ConsoleUtils.csWindowsUtils.cs, sử dụng lệnh: csc /out:MyLibrary.dll /target:library ConsoleUtils.cs WindowsUtils.cs. Sau khi thư viện được tạo, một ứng dụng khác có thể sử dụng các chức năng bên trong nó bằng cách thêm một tham chiếu lúc biên dịch. Ví dụ, để biên dịch MyApp.cs sử dụng MyLibrary.dll, lệnh sẽ là: csc /reference:MyLibrary.dll MyApp.cs. Nếu thư viện không nằm trong cùng thư mục, có thể dùng cờ /lib để chỉ định đường dẫn. Việc tạo tên mạnh cho thư viện là rất quan trọng để có thể cài đặt nó vào Global Assembly Cache (GAC) và chia sẻ một cách an toàn.

V. Phương pháp bảo mật Assembly với kỹ thuật tạo tên mạnh

Bảo mật và đảm bảo tính toàn vẹn của mã lệnh là một yêu cầu cơ bản trong phát triển phần mềm hiện đại. Trong môi trường .NET Framework, giải pháp lập trình cốt lõi cho vấn đề này là tạo tên mạnh (strong name) cho một assembly. Một tên mạnh cung cấp cho assembly một định danh duy nhất trên toàn cầu, bao gồm tên văn bản đơn giản, số phiên bản, thông tin văn hóa (culture) và một token khóa công khai. Quan trọng hơn, nó chứa một chữ ký số được tạo bằng khóa riêng của nhà phát triển. Chữ ký này đảm bảo hai điều: tính xác thực (assembly thực sự đến từ nhà phát triển sở hữu khóa riêng) và tính toàn vẹn (assembly không bị thay đổi kể từ khi nó được ký). Quá trình tạo tên mạnh bắt đầu bằng việc tạo một cặp khóa công khai/riêng tư bằng công cụ Strong Name (sn.exe). Khóa riêng phải được giữ bí mật tuyệt đối, trong khi khóa công khai được phân phối cùng với assembly. Sau đó, nhà phát triển sử dụng các thuộc tính (attribute) trong mã nguồn, như AssemblyKeyFileAttribute, để chỉ định file chứa cặp khóa cho trình biên dịch. Khi biên dịch, trình biên dịch sẽ tính toán một mã băm (hash) của manifest assembly, mã hóa mã băm này bằng khóa riêng để tạo chữ ký số, và nhúng cả chữ ký số lẫn khóa công khai vào assembly. Khi bộ thực thi nạp một assembly có tên mạnh, nó sẽ thực hiện quy trình xác minh: giải mã chữ ký bằng khóa công khai để lấy lại mã băm gốc, sau đó tính toán lại mã băm của assembly hiện tại và so sánh hai giá trị. Nếu chúng khớp nhau, assembly được xem là hợp lệ. Kỹ thuật này là nền tảng cho việc cài đặt assembly vào Global Assembly Cache (GAC) và cấu hình các chính sách bảo mật truy xuất mã lệnh.

5.1. Quy trình tạo cặp khóa công khai và riêng tư với sn.exe

Công cụ Dòng lệnh Strong Name (sn.exe) là tiện ích chính để quản lý các khóa cho việc tạo tên mạnh. Để tạo một cặp khóa mới và lưu chúng vào một file, sử dụng lệnh: sn –k MyKey.snk. File MyKey.snk này chứa cả khóa công khai và khóa riêng. Điều cực kỳ quan trọng là phải bảo vệ khóa riêng. Theo tài liệu, "Việc giữ bí mật khóa riêng là cần thiết vì người truy xuất vào khóa riêng của bạn có thể thay đổi assembly và tạo một tên mạnh mới". Khóa công khai có thể được trích xuất từ file này để phân phối cho các nhà phát triển khác trong nhóm mà không gây rủi ro bảo mật.

5.2. Gán tên mạnh cho một Assembly trong quá trình biên dịch

Sau khi có cặp khóa, việc gán tên mạnh cho một assembly được thực hiện bằng cách thêm các thuộc tính vào một trong các file mã nguồn. Nếu cặp khóa được lưu trong file MyKey.snk, sử dụng thuộc tính: [assembly: System.Reflection.AssemblyKeyFileAttribute("MyKey.snk")]. Ngoài ra, có thể chỉ định phiên bản và văn hóa cho assembly bằng AssemblyVersionAttributeAssemblyCultureAttribute. Khi trình biên dịch C# thấy các thuộc tính này, nó sẽ tự động thực hiện quá trình ký trong khi xây dựng file thực thi hoặc thư viện. Kết quả là một assembly có chữ ký số, sẵn sàng để được xác minh và tin cậy.

5.3. Kỹ thuật hoãn ký Assembly Delay Signing trong môi trường nhóm

Trong các môi trường phát triển lớn, việc phân phối khóa riêng cho mọi thành viên trong nhóm là một rủi ro bảo mật lớn. .NET Framework cung cấp một giải pháp lập trình tinh vi gọi là hoãn việc ký assembly (delay signing). Quá trình này cho phép các nhà phát triển biên dịch assembly chỉ với khóa công khai. Assembly được tạo ra sẽ có không gian dành riêng cho chữ ký số nhưng chưa được ký thực sự. Để thực hiện, cần áp dụng thuộc tính [assembly: System.Reflection.AssemblyDelaySignAttribute(true)]. Sau khi quá trình phát triển và kiểm thử hoàn tất, một người có thẩm quyền (signing authority) sẽ sử dụng khóa riêng để thực hiện việc ký cuối cùng trước khi phát hành. Kỹ thuật này cân bằng giữa nhu cầu phát triển linh hoạt và yêu cầu bảo mật nghiêm ngặt.

16/07/2025

Trích đoạn nội dung tài liệu

Chương 1: Phát triển ứng dụng Để xây dựng lớp ConsoleUtils thành một ứng dụng Console có tên là ConsoleUtils.exe, sử dụng lệnh: csc /target:exe ConsoleUtils.cs Bạn có thể chạy file thực thi trực tiếp từ dòng lệnh. Khi chạy, phương thức Main của ứng dụng ConsoleUtils.exe yêu cầu bạn nhập tên và sau đó hiển thị thông điệp chào mừng như sau: Please enter your name : Binh Phuong Welcome to Microsoft .NET Framework, Binh Phuong Thực tế, ứng dụng hiếm khi chỉ gồm một file mã nguồn. Ví dụ, lớp HelloWorld dưới đây sử dụng lớp ConsoleUtils để hiển thị thông điệp “Hello, world” lên màn hình (HelloWorld nằm trong file HelloWorld. public class HelloWorld { public static void Main() { ConsoleUtils.WriteString("Hello, world"); } } Để xây dựng một ứng dụng Console gồm nhiều file mã nguồn, bạn phải chỉ định tất cả các file mã nguồn này trong đối số dòng lệnh.

Ví dụ, lệnh sau đây xây dựng ứng dụng MyFirstApp.exe từ các file mã nguồn HelloWorld.cs và ConsoleUtils.cs: csc /target:exe /main:HelloWorld /out:MyFirstApp.cs Đối số /out chỉ định tên của file thực thi sẽ được tạo ra. Nếu không được chỉ định, tên của file thực thi sẽ là tên của file mã nguồn đầu tiên—trong ví dụ trên là HelloWorld. Vì cả hai lớp HelloWorld và ConsoleUtils đều có phương thức Main, trình biên dịch không thể tự động quyết định đâu là điểm nhập cho file thực thi. Bạn phải sử dụng đối số /main để chỉ định tên của lớp chứa điểm nhập cho ứng dụng của bạn.

Tạo ứng dụng dựa-trên-Windows  Bạn cần xây dựng một ứng dụng cung cấp giao diện người dùng đồ họa (GUI) dựa-trên-Windows Form.  Hiện thực một phương thức tĩnh Main trong ít nhất một file mã nguồn. Trong Main, tạo một thể hiện của một lớp thừa kế từ lớp System. Truyền đối tượng này cho phương thức tĩnh Run của lớp System.

Sử dụng đối số /target:winexe khi biên dịch assembly của bạn bằng trình biên dịch C# (csc. Việc xây dựng một ứng dụng có giao diện người dùng đồ họa Windows đơn giản hoàn toàn khác xa việc phát triển một ứng dụng dựa-trên-Windows hoàn chỉnh. Tuy nhiên, bất kể viết 34 Chương 1: Phát triển ứng dụng một ứng dụng đơn giản như Hello World hay viết phiên bản kế tiếp cho Microsoft Word, bạn cũng phải thực hiện những việc sau: • Tạo một lớp thừa kế từ lớp System.Form cho mỗi form cần cho ứng dụng. • Trong mỗi lớp form, khai báo các thành viên mô tả các điều kiểm trên form, ví dụ Button, Label, ListBox, TextBox.

Các thành viên này nên được khai báo là private hoặc ít nhất cũng là protected để các phần tử khác của chương trình không truy xuất trực tiếp chúng được. Nếu muốn cho phép truy xuất các điều kiểm này, hiện thực các thành viên cần thiết trong lớp form để cung cấp việc truy xuất gián tiếp (kiểm soát được) đến các điều kiểm nằm trong. • Trong lớp form, khai báo các phương thức thụ lý các sự kiện do các điều kiểm trên form sinh ra, chẳng hạn việc nhắp vào Button, việc nhấn phím khi một TextBox đang tích cực. Các phương thức này nên được khai báo là private hoặc protected và tuân theo mẫu sự kiện .NET chuẩn (sẽ được mô tả trong mục 16.

Trong các phương thức này (hoặc trong các phương thức được gọi bởi các các phương thức này), bạn sẽ định nghĩa các chức năng của ứng dụng. • Khai báo một phương thức khởi dựng cho lớp form để tạo các điều kiểm trên form và cấu hình trạng thái ban đầu của chúng (kích thước, màu, nội dung…). Phương thức khởi dựng này cũng nên liên kết các phương thức thụ lý sự kiện của lớp với các sự kiện tương ứng của mỗi điều kiểm. • Khai báo phương thức tĩnh Main—thường là một phương thức của lớp tương ứng với form chính của ứng dụng.

Phương thức này là điểm bắt đầu của ứng dụng và có các dạng như đã được đề cập ở mục 1. Trong phương thức Main, tạo một thể hiện của form chính và truyền nó cho phương thức tĩnh Application. Phương thức Run hiển thị form chính và khởi chạy một vòng lặp thông điệp chuẩn trong tiểu trình hiện hành, chuyển các tác động từ người dùng (nhấn phím, nhắp chuột…) thành các sự kiện gửi đến ứng dụng. Lớp WelcomeForm trong ví dụ dưới đây minh họa các kỹ thuật trên.

Khi chạy, nó yêu cầu người dùng nhập vào tên rồi hiển thị một MessageBox chào mừng.Forms; public class WelcomeForm : Form { // Các thành viên private giữ tham chiếu đến các điều kiểm. private Label label1; private TextBox textBox1; private Button button1; // Phương thức khởi dựng (tạo một thể hiện form 35 Chương 1: Phát triển ứng dụng // và cấu hình các điều kiểm trên form). public WelcomeForm() { // Tạo các điều kiểm trên form.label1 = new Label(); this.textBox1 = new TextBox(); this.button1 = new Button(); // Tạm hoãn layout logic của form trong khi // chúng ta cấu hình và bố trí các điều kiểm.Location = new System.Name = "label1"; this.Size = new System.Text = "Please enter your name:"; // Cấu hình TextBox (nhận thông tin từ người dùng).Location = new System.Name = "textBox1"; this.Text = ""; // Cấu hình Buton (người dùng nhấn vào sau khi nhập tên).Location = new System.Name = "button1"; this.Text = "Enter"; this.Click += new System.button1_Click); // Cấu hình WelcomeForm và thêm các điều kiểm.ClientSize = new System.Name = "form1"; 36 Chương 1: Phát triển ứng dụng this.NET Framework"; // Phục hồi layout logic của form ngay khi // tất cả các điều kiểm đã được cấu hình. public static void Main() { Application.

private void button1_Click(object sender, System.EventArgs e) { // Ghi ra Console.WriteLine("User entered: " + textBox1.Text); // Hiển thị lời chào trong MessageBox.Show("Welcome to Microsoft .NET Framework, " + textBox1.NET Framework"); } } 37 Chương 1: Phát triển ứng dụng Hình 1.1 Một ứng dụng Windows Form đơn giản Để xây dựng lớp WelcomeForm (trong file WelcomeForm.cs) thành một ứng dụng, sử dụng lệnh: csc /target:winexe WelcomeForm.cs Đối số /target:winexe báo cho trình biên dịch biết đây là ứng dụng dựa-trên-Windows. Do đó, trình biên dịch sẽ xây dựng file thực thi sao cho không có cửa sổ Console nào được tạo ra khi bạn chạy ứng dụng. Nếu bạn sử dụng /target:exe khi xây dựng một ứng dụng Windows Form thay cho /target:winexe thì ứng dụng vẫn làm việc tốt, nhưng sẽ tạo ra một cửa sổ Console khi chạy. Mặc dù điều này không được ưa chuộng trong một ứng dụng hoàn chỉnh, cửa sổ Console vẫn hữu ích nếu bạn cần ghi ra các thông tin gỡ rối hoặc đăng nhập khi đang phát triển và thử nghiệm một ứng dụng Windows Form.

Bạn có thể ghi ra Console bằng phương thức Write và WriteLine của lớp System. Ứng dụng WelcomeForm.exe trong hình 1.1 hiển thị lời chào người dùng có tên là Binh Phuong. Phiên bản này của ứng dụng được xây dựng bằng đối số /target:exe, nên có cửa sổ Console để hiển thị kết quả của dòng lệnh Console.WriteLine trong phương thức thụ lý sự kiện button1_Click.  Việc xây dựng một ứng dụng GUI đồ sộ thường tốn nhiều thời gian do phải tạo đối tượng, cấu hình và liên kết nhiều form và điều kiểm.

Nhưng may mắn là Microsoft Visual Studio .NET tự động hóa hầu hết các hoạt động này. Nếu không có công cụ như Microsoft Visual Studio .NET thì việc xây dựng một ứng dụng đồ họa đồ sộ sẽ rất lâu, nhàm chán và dễ sinh ra lỗi. Tạo và sử dụng module  Bạn cần thực hiện các công việc sau: • Tăng hiệu quả thực thi và sử dụng bộ nhớ của ứng dụng bằng cách bảo đảm rằng bộ thực thi nạp các kiểu ít được sử dụng chỉ khi nào cần thiết. 38 Chương 1: Phát triển ứng dụng • Biên dịch các kiểu được viết trong C# thành một dạng có thể sử dụng lại được trong các ngôn ngữ.

• Sử dụng các kiểu được phát triển bằng một ngôn ngữ khác bên trong ứng dụng C# của bạn.  Sử dụng đối số /target:module (của trình biên dịch C#) để xây dựng mã nguồn C# của bạn thành một module. Sử dụng đối số /addmodule để kết hợp các module hiện có vào assembly của bạn. Module là các khối cơ bản tạo dựng nên các assembly.

Module bao gồm một file đơn chứa: • Mã ngôn ngữ trung gian (Microsoft Intermediate Language—MSIL): Được tạo từ mã nguồn C# trong quá trình biên dịch. • Siêu dữ liệu (metadata): Mô tả các kiểu nằm trong module. • Các tài nguyên (resource): Chẳng hạn icon và string table, được sử dụng bởi các kiểu trong module. Assembly gồm một hay nhiều module và một manifest.

Khi chỉ có một module, module và manifest thường được xây dựng thành một file cho thuận tiện. Khi có nhiều module, assembly là một nhóm luận lý của nhiều file được triển khai như một thể thống nhất. Trong trường hợp này, manifest có thể nằm trong một file riêng hay chung với một trong các module. Việc xây dựng một assembly từ nhiều module gây khó khăn cho việc quản lý và triển khai assembly; nhưng trong một số trường hợp, cách này có nhiều lợi ích, bao gồm: • Bộ thực thi sẽ chỉ nạp một module khi các kiểu định nghĩa trong module này được yêu cầu.

Do đó, khi có một tập các kiểu mà ứng dụng ít khi dùng, bạn có thể đặt chúng trong một module riêng mà bộ thực thi chỉ nạp khi cần. Việc này có các lợi ích sau: ▪ Tăng hiệu quả thực thi, đặc biệt khi ứng dụng được nạp qua mạng. ▪ Giảm thiểu nhu cầu sử dụng bộ nhớ. • Khả năng sử dụng nhiều ngôn ngữ khác nhau để viết các ứng dụng chạy trên bộ thực thi ngôn ngữ chung (Common Language Runtime—CLR) là một thế mạnh của.

Tuy nhiên, trình biên dịch C# không thể biên dịch mã nguồn được viết bằng Microsoft Visual Basic .NET hay COBOL .NET trong assembly của bạn. Bạn phải sử dụng trình biên dịch của ngôn ngữ đó biên dịch mã nguồn thành MSIL theo một cấu trúc mà trình biên dịch C# có thể hiểu được—đó là module. Tương tự, nếu muốn lập trình viên của các ngôn ngữ khác sử dụng các kiểu được phát triển bằng C#, bạn phải xây dựng chúng thành một module. Để biên dịch file nguồn ConsoleUtils.cs thành một module, sử dụng lệnh: csc /target:module ConsoleUtils.cs Lệnh này sẽ cho kết quả là một file có tên là ConsoleUtils.

Phần mở rộng netmodule là phần mở rộng mặc định cho module, và tên file trùng với tên file nguồn C#. 39 Chương 1: Phát triển ứng dụng Bạn cũng có thể xây dựng một module từ nhiều file nguồn, cho kết quả là một file (module) chứa MSIL và siêu dữ liệu cho các kiểu chứa trong tất cả file nguồn. Ví dụ, lệnh: csc /target:module ConsoleUtils.cs biên dịch hai file nguồn ConsoleUtils.cs và WindowsUtils.cs thành một module có tên là ConsoleUtils. Tên của module được đặt theo tên file nguồn đầu tiên trừ khi bạn chỉ định cụ thể bằng đối số /out.

Ví dụ, lệnh: csc /target:module /out:Utilities.cs sẽ cho kết quả là file Utilities. Để xây dựng một assembly gồm nhiều module, sử dụng đối số /addmodule.

Nội dung được bảo vệ bản quyền — Tải xuống đầy đủ