DỮ LIỆU CÓ CẤU TRÚC, PHƯƠNG THỨC VÀ XỬ LÝ NGOẠI LỆ TRONG C. 1. Dữ liệu có cấu trúc 1.1. Mảng (Array) Mảng là một cấu trúc dữ liệu cấu tạo bởi một số biến được gọi là những phần tử mảng. Tất cả các phần tử này đều thuộc một kiểu dữ liệu. Người lập trình có thể truy xuất phần tử thông qua chỉ số (index). Chỉ số bắt đầu bằng 0. Người ta thường chia mảng thành 2 loại: Mảng một chiều và mảng nhiều chiều. Đối với mảng nhiều chiều giáo trình này chỉ trình bày mảng hai chiều bởi vì mảng hai chiều là đặc trưng tiêu biểu cho mảng nhiều chiều 1.1.1. Mảng một chiều Cú pháp khai báo + Khai báo không khởi tạo kích thước và giá trị: Tên_mảng; + Khai báo có khởi tạo kích thước nhưng không khởi tạo giá trị ban đầu: Tên_mảng = new ; + Khai báo có khởi tạo kích thước và khởi tạo giá trị ban đầu: Tên_mảng = new {giá trị 1, giá trị 2, giá trị 3, ...}; hoặc: Tên_mảng = {giá trị 1, giá trị 2, giá trị 3, ...}
LẬP TRÌNH NET BÀI DỮ LIỆU CĨ CẤU TRÚC, PHƯƠNG THỨC VÀ XỬ LÝ NGOẠI LỆ TRONG C# Dữ liệu có cấu trúc 1.1 Mảng (Array) Mảng cấu trúc liệu cấu tạo số biến gọi phần tử mảng Tất phần tử thuộc kiểu liệu Người lập trình truy xuất phần tử thơng qua số (index) Chỉ số bắt đầu Người ta thường chia mảng thành loại: Mảng chiều mảng nhiều chiều Đối với mảng nhiều chiều giáo trình trình bày mảng hai chiều mảng hai chiều đặc trưng tiêu biểu cho mảng nhiều chiều 1.1.1 Mảng chiều Cú pháp khai báo + Khai báo khơng khởi tạo kích thước giá trị: [ ] Tên_mảng; + Khai báo có khởi tạo kích thước khơng khởi tạo giá trị ban đầu: [ ] Tên_mảng = new []; + Khai báo có khởi tạo kích thước khởi tạo giá trị ban đầu: [ ] Tên_mảng = new [] {giá trị 1, giá trị 2, giá trị 3, }; hoặc: [ ] Tên_mảng = {giá trị 1, giá trị 2, giá trị 3, }; Ví dụ 2.1: int[ int[ int[ int[ ] ] ] ] a; a = new int[10]; b = new int[5]{2,10,4,8,5}; b = {2, 10, 4, 8, 5}; Cách sử dụng Để làm việc với mảng, người lập trình thường can thiệp trực tiếp vào phần tử mảng thông qua số index với cú pháp Tên_mảng[chỉ số] Ví dụ 2.2: x = a[0]; st = b[i]; b[1] = x; Để lấy kích thước array, sử dụng thuộc tính Length Một số phương thức thường dùng liệu kiểu array là: Học kết hợp Trang LẬP TRÌNH NET - Array.Sort(arr): hàm tĩnh, sử dụng để xếp array arr; arr array phần tử có kiểu định nghĩa sẵn C# - Array.Reverse(arr): hàm tĩnh, sử dụng để đảo ngược vị trí phần tử có array arr Ví dụ 2.3: Minh họa việc khai báo array gồm string, xếp theo thứ tự ABC, đảo ngược phần tử, in phần tử ra: string[] hoTen = { "Nguyen Van Trung", "Nguyen Hoang Ha", "Tran Nguyen Phong" }; //in danh sach cac phan tu array for (int i = 0; i < hoTen.Length; i++) Console.WriteLine(hoTen[i]); Array.Sort(hoTen); Array.Reverse(hoTen); //in danh sach cac phan tu array su dung cu phap foreach foreach (string stHoTen in hoTen) Console.WriteLine(stHoTen); 1.1.2 Mảng hai chiều Cú pháp khai báo [ , ] Tên_mảng; [ , ] Tên_mảng = new [số hàng, số cột]; [ , ] Tên_mảng = new [ , ]{}; [ , ] Tên_mảng = {}; Ví dụ 2.4: //khai báo mảng số ngun có dòng cột int[,] myRectArray = new int[2,3]; //khai báo mảng số nguyên hàng cột int[,] myRectArray = new int[,]{ {1,2},{3,4},{5,6},{7,8}}; //khai báo mảng string có dòng cột string[,] beatleName ={ {"Lennon","John"}, {"McCartney","Paul"}, {"Harrison","George"}, {"Starkey","Richard"} }; Cách sử dụng Để làm việc với mảng hai chiều, người lập trình can thiệp trực tiếp vào phần tử mảng thông qua số hàng số cột Ví dụ 2.5: A[0,1]=2; //Gán giá trị vào phần tử hàng cột Console.Write(A[2,3]);//In giá trị phần tử hàng cột hình Vì cấu trúc lưu trữ ma trận bao gồm hàng cột nên người lập trình thường sử dụng hai vịng lặp lồng để thực việc duyệt ma trận Ví dụ 2.6: Duyệt ma trận cách sử dụng hai vịng lặp lồng nhau, q trình lặp, chương trình hiển thị chuỗi ma trận: using System; class Program Học kết hợp Trang LẬP TRÌNH NET { static void Main(string[] args) { string[,] beatleName = { { "Lennom", "John" }, { "McCartney", "Paul" }, { "Harrison", "George" }, { "Starkey", "Richard" } }; for (int i = 0; i < 4; i++) { for (int j = 0; j < 2; j++) { Console.Write(beatleName[i, j] + " "); } Console.WriteLine(); } Console.ReadLine(); } } 1.2 Chuỗi ký tự 1.2.1 Khái niệm Chuỗi đối tượng kiểu String, có giá trị văn Bên trong, văn lưu trữ dạng sưu tập đọc đối tượng kiểu Char Khơng có ký tự kết thúc null cuối chuỗi C#, chuỗi C# chứa số ký tự null ('\0') Thuộc tích Length chuỗi đại diện cho số đối tượng kiểu Char mà chứa, khơng phải số lượng ký tự Unicode Để truy cập mã Unicode riêng lẻ chuỗi, sử dụng đối tượng StringInfo string vs System.String Trong C #, string từ khóa dành cho Chuỗi Do đó, String string tương đương, bất chấp khuyến nghị nên sử dụng từ khóa cung cấp string hoạt động khơng có using System Các lớp String cung cấp nhiều phương thức để tạo, thao tác, so sánh chuỗi cách an tồn Ngồi ra, ngơn ngữ C# nạp chồng số toán tử để đơn giản hóa hoạt động chuỗi phổ biến 1.2.2 Khai báo khởi tạo chuỗi Ta khai báo khởi tạo chuỗi theo nhiều cách khác nhau, ví dụ sau Ví dụ 2.7: // Declare without initializing string message1; // Initialize to null string message2 = null; // Initialize as an empty string // Use the Empty constant instead of the literal "" string message3 = System.String.Empty; // Initialize with a regular string literal string oldPath = "c:\\Program Files\\Microsoft Visual Studio 8.0"; // Initialize with a verbatim string literal string newPath = @"c:\Program Files\Microsoft Visual Studio 9.0"; // Use System.String if you prefer Học kết hợp Trang LẬP TRÌNH NET System.String greeting = "Hello World!"; // In local variables (i.e within a method body) // you can use implicit typing var temp = "I'm still a strongly-typed System.String!"; // Use a const string to prevent 'message4' from // being used to store another string value const string message4 = "You can't get rid of me!"; // Use the String constructor only when creating // a string from a char*, char[], or sbyte* See // System.String documentation for details char[] letters = { 'A', 'B', 'C' }; string alphabet = new string(letters); Lưu ý ta không sử dụng toán tử new để tạo đối tượng chuỗi ngoại trừ khởi tạo chuỗi mảng ký tự Khởi tạo chuỗi với giá trị số Empty để tạo đối tượng String chuỗi có độ dài khơng Biểu diễn theo nghĩa đen chuỗi có độ dài "" Bằng cách khởi tạo chuỗi với giá trị Empty thay null, ta giảm khả xảy NullReferenceException Người lập trình nên sử dụng phương thức IsNullOrEmpty (String) tĩnh để xác minh giá trị chuỗi trước cố gắng truy cập vào Tính bất biến đối tượng chuỗi Đối tượng chuỗi bất biến: chúng thay đổi sau tạo Tất phương thức String toán tử C# xuất để sửa đổi chuỗi thực trả kết đối tượng chuỗi Trong ví dụ sau, nội dung s1và s2 nối với để tạo thành chuỗi đơn, hai chuỗi ban đầu không bị sửa đổi Các tốn tử += tạo chuỗi có chứa nội dung kết hợp Đối tượng gán cho biến s1và đối tượng ban đầu tương ứng với s1 giải phóng để thu gom rác khơng có biến khác giữ tham chiếu đến Ví dụ 2.8: string s1 = "A string is more "; string s2 = "than the sum of its chars."; // // // s1 Concatenate s1 and s2 This actually creates a new string object and stores it in s1, releasing the reference to the original object += s2; System.Console.WriteLine(s1); // Output: A string is more than the sum of its chars Bởi "modification" chuỗi thực tạo chuỗi mới, phải thận trọng tạo tham chiếu đến chuỗi Nếu bạn tạo tham chiếu đến chuỗi sau "modify" chuỗi ban đầu, tham chiếu tiếp tục trỏ đến đối tượng ban đầu thay đối tượng tạo chuỗi sửa đổi Đoạn mã sau minh họa điều Ví dụ 2.9: Học kết hợp Trang LẬP TRÌNH NET string s1 = "Hello "; string s2 = s1; s1 += "World"; System.Console.WriteLine(s2); //Output: Hello 1.2.3 Sửa đổi nội dung chuỗi Thay văn Đoạn mã sau tạo chuỗi cách thay văn có văn khác Ví dụ 2.10: using System; string source = "The mountains are behind the clouds today."; // Replace one substring with another with String.Replace // Only exact matches are supported var replacement = source.Replace("mountains", "peaks"); Console.WriteLine($"The source string is "); Console.WriteLine($"The updated string is "); Đoạn mã thể thuộc tính bất biến chuỗi Ta thấy ví dụ chuỗi gốc source, khơng sửa đổi Phương thức String.Replace tạo string có chứa sửa đổi Phương thức Replace thay chuỗi ký tự cụ thể chuỗi Trong hai trường hợp, lần xuất văn tìm thấy thay Ví dụ sau thay tất ký tự trắng ' ' ký tự gạch '_' Ví dụ 2.10: using System; string source = "The mountains are behind the clouds today."; // Replace all occurrences of one char with another var replacement = source.Replace(' ', '_'); Console.WriteLine(source); Console.WriteLine(replacement); Chuỗi nguồn không thay đổi chuỗi trả với chuỗi thay Cắt bỏ khoảng trắng Ta sử dụng phương thức String.Trim(), String.TrimStart() String.TrimEnd() để loại bỏ khoảng trắng đầu cuối Đoạn mã sau cho thấy ví dụ loại Chuỗi nguồn không thay đổi; phương thức trả chuỗi với nội dung sửa đổi Ví dụ 2.11: // Remove trailing and leading white space using System; Học kết hợp Trang LẬP TRÌNH NET string source = " I'm wider than I need to be // Store the results in a new string variable var trimmedResult = source.Trim(); var trimLeading = source.TrimStart(); var trimTrailing = source.TrimEnd(); Console.WriteLine($""); Console.WriteLine($""); Console.WriteLine($""); "; Console.WriteLine($""); Xóa văn Ta xóa văn khỏi chuỗi phương thức String.Remove() Phương thức loại bỏ số ký tự mục cụ thể Ví dụ sau cho thấy cách sử dụng String.IndexOf theo sau Remove để xóa văn khỏi chuỗi Ví dụ 2.12: using System; string source = "Many mountains are behind many clouds today."; // Remove a substring from the middle of the string string toRemove = "many "; string result = string.Empty; int i = source.IndexOf(toRemove); if (i >= 0) { result = source.Remove(i, toRemove.Length); } Console.WriteLine(source); Console.WriteLine(result); Thay mẫu phù hợp Ta sử dụng biểu thức quy (regular expressions) để thay mẫu đối sánh văn văn mới, xác định mẫu Ví dụ sau sử dụng lớp System.Text.RegularExpressions.Regex để tìm mẫu chuỗi nguồn thay cách viết hoa thích hợp Phương thức Regex.Replace(String, String, MatchEvaluator, RegexOptions) nhận hàm cung cấp logic phép thay làm đối số Trong ví dụ này, hàm LocalReplaceMatchCase hàm cục khai báo bên phương thức mẫu LocalReplaceMatchCase sử dụng lớp System.Text.StringBuilder để xây dựng chuỗi thay với cách viết hoa thích hợp Biểu thức quy hữu ích để tìm kiếm thay văn tuân theo mẫu, thay văn biết Mẫu tìm kiếm "the\s" tìm kiếm từ "the" theo sau ký tự khoảng trắng Phần mẫu đảm bảo khơng khớp với từ "there" chuỗi nguồn Để biết thêm thông tin thành phần ngơn ngữ biểu thức quy, tìm hiểu thêm Regular Expression Language Ví dụ 2.13: using System; string source = "The mountains are still there behind the clouds today."; Học kết hợp Trang LẬP TRÌNH NET // Use Regex.Replace for more flexibility // Replace "the" or "The" with "many" or "Many" // using System.Text.RegularExpressions string replaceWith = "many "; source = System.Text.RegularExpressions.Regex.Replace(source, "the\\s", LocalReplaceMatchCase, System.Text.RegularExpressions.RegexOptions.IgnoreCase); Console.WriteLine(source); string LocalReplaceMatchCase(System.Text.RegularExpressions.Match matchExpression) { // Test whether the match is capitalized if (Char.IsUpper(matchExpression.Value[0])) { // Capitalize the replacement string System.Text.StringBuilder replacementBuilder = new System.Text.StringBuilder(replaceWith); replacementBuilder[0] = Char.ToUpper(replacementBuilder[0]); return replacementBuilder.ToString(); } else { return replaceWith; } } Phương thức StringBuilder.ToString() trả chuỗi bất biến với nội dung đối tượng StringBuilder Sửa đổi ký tự riêng lẻ Ta tạo mảng ký tự từ chuỗi, sửa đổi nội dung mảng, sau tạo chuỗi từ nội dung sửa đổi mảng Ví dụ sau cho thấy cách thay tập hợp ký tự chuỗi Đầu tiên, sử dụng phương thức String.ToCharArray() để tạo mảng ký tự Nó sử dụng phương thức IndexOf() để tìm mục bắt đầu từ "fox" Ba ký tự thay từ khác Cuối cùng, chuỗi xây dựng từ mảng ký tự cập nhật Ví dụ 2.14: using System; string phrase = "The quick brown fox jumps over the fence"; Console.WriteLine(phrase); char[] phraseAsChars = phrase.ToCharArray(); int animalIndex = phrase.IndexOf("fox"); if (animalIndex != -1) { phraseAsChars[animalIndex++] = 'c'; phraseAsChars[animalIndex++] = 'a'; phraseAsChars[animalIndex] = 't'; } string updatedPhrase = new string(phraseAsChars); Console.WriteLine(updatedPhrase); Học kết hợp Trang LẬP TRÌNH NET Lập trình xây dựng nội dung chuỗi Vì chuỗi bất biến, ví dụ trước tạo chuỗi tạm thời tạo mảng ký tự Trong tình hiệu suất cao, nên tránh việc truy cập nhớ heap .NET cung cấp phương thức String.Create() cho phép ta “lập trình” ký tự nội dung chuỗi thơng qua lệnh callback tránh cấp phát chuỗi tạm thời trung gian Ví dụ 2.15: // constructing a string from a char array, prefix it with some additional characters using System; char[] chars = { 'a', 'b', 'c', 'd', '\0' }; int length = chars.Length + 2; string result = string.Create(length, chars, (Span strContent, char[] charArray) => { strContent[0] = '0'; strContent[1] = '1'; for (int i = 0; i < charArray.Length; i++) { strContent[i + 2] = charArray[i]; } }); Console.WriteLine(result); Bạn sửa đổi chuỗi khối cố định với mã khơng an tồn, bạn không nên sửa đổi nội dung chuỗi sau tạo chuỗi Làm phá vỡ thứ theo cách khơng thể đốn trước 1.2.4 Regular Verbatim String Sử dụng ký tự chuỗi regular bạn phải nhúng ký tự đặc biệt C# cung cấp, thể ví dụ sau Ví dụ 2.16: string columns = "Column 1\tColumn 2\tColumn 3"; //Output: Column Column Column string rows = "Row 1\r\nRow 2\r\nRow 3"; /* Output: Row Row Row */ string title = "\"The \u00C6olean Harp\", by Samuel Taylor Coleridge"; //Output: "The Ỉolean Harp", by Samuel Taylor Coleridge Bảng sau thể số ký tự đặc biệt C#: Escape Character name sequence Học kết hợp Unicode encoding Trang LẬP TRÌNH NET \' Single quote 0x0027 \" Double quote 0x0022 \\ Backslash 0x005C \0 Null 0x0000 \a Alert 0x0007 \b Backspace 0x0008 \f Form feed 0x000C \n New line 0x000A \r Carriage return 0x000D \t Horizontal tab 0x0009 \v Vertical tab 0x000B \u Unicode escape sequence (UTF-16) \uHHHH \U Unicode escape sequence (UTF-32) \U00HHHHHH Unicode escape sequence similar to "\u" except with variable length \xH[H][H][H] \x (range: 0000 - FFFF; example: \u00E7 = "ỗ") (range: 000000 - 10FFFF; example: \U0001F47D = " ") (range: - FFFF; example: \x00E7 or \x0E7 or \xE7 = "ỗ") S dng chui verbatim thun tin dễ đọc văn chuỗi chứa ký tự gạch chéo ngược, ví dụ đường dẫn tệp Bởi chuỗi verbatim bảo tồn ký tự xuống dòng phần văn chuỗi, chúng sử dụng để khởi tạo chuỗi nhiều dòng Sử dụng dấu ngoặc kép để nhúng dấu ngoặc kép bên chuỗi verbatim Ví dụ sau cho thấy số cách sử dụng phổ biến cho chuỗi verbatim Ví dụ 2.17: string filePath = @"C:\Users\scoleridge\Documents\"; //Output: C:\Users\scoleridge\Documents\ string text = @"My pensive SARA ! thy soft cheek reclined Thus on mine arm, most soothing sweet it is To sit beside our Cot, "; /* Output: Học kết hợp Trang LẬP TRÌNH NET My pensive SARA ! thy soft cheek reclined Thus on mine arm, most soothing sweet it is To sit beside our Cot, */ string quote = @"Her name was ""Sara."""; //Output: Her name was "Sara." 1.3 Cấu trúc: 1.3.1 Khái niệm Struct Struct kiểu liệu có cấu trúc, kết hợp từ kiểu liệu nguyên thuỷ người lập trình định nghĩa để thuận tiện việc quản lý liệu lập trình Xét tốn sau: Ta cần lưu trữ thơng tin nhân cơng ty gồm có thơng tin • • • • Mã nhân viên Họ tên Nơi sinh Số chứng minh thư nhân dân Khi đó, để lưu thông tin nhân viên ta cần biến chứa thơng tin Việc phải trì thao tác với biến riêng lẻ khiến cơng việc trở nên phiền tối, khó thao tác, khó kiểm sốt Từ người ta đưa khái niệm kiểu liệu có cấu trúc để giải vấn đề Ý tưởng đóng gói thơng tin vào đối tượng Như thay phải khai báo 40 biến cho 10 nhân viên ta cần khai báo mảng 10 phần tử mà phần tử có kiểu liệu ta định nghĩa Đặc điểm struct: • Là kiểu liệu tham trị (kiểu liệu tham trị trình bày trước, phần Kiểu liệu) • Dùng để đóng gói trường liệu khác có liên quan đến • Bên struct ngồi biến có kiểu liệu cịn có phương thức, struct khác • Muốn sử dụng phải khởi tạo cấp phát vùng nhớ cho đối tượng thơng qua tốn tử new • Struct không phép kế thừa (khái niệm kế thừa trình bày phần Lập trình hướng đối tượng) 1.3.2 Khai báo sử dụng Struct Cú pháp khai báo: struct Học kết hợp Trang 10 LẬP TRÌNH NET { public ; } Trong đó: • tên kiểu liệu tự đặt tuân thủ theo quy tắc đặt tên biến • danh sách biến thành phần khai báo khai báo biến bình thường • Từ khố public từ khoá định phạm vi truy cập Trong ngữ cảnh hiểu từ khố giúp cho người khác truy xuất để sử dụng Ví dụ 2.18: struct Coordinate { public int x; public int y; } Coordinate point; Console.Write(point.x); // Compile time error point.x = 10; point.y = 20; Console.Write(point.x); //output: 10 Console.Write(point.y); //output: 20 Nhận xét chung: • Kiểu liệu Coordinate dùng làm kiểu liệu cho biến, parametter cho phương thức Ngồi cịn làm kiểu trả cho phương thức • Các thành phần liệu bên truy xuất thông qua dấu “.” • Vì struct kiểu tham trị nên truyền vào phương thức giá trị sau kết thúc phương thức khơng thay đổi Do cần sử dụng từ khố out để cập nhật giá trị thay đổi kết thúc phương thức 1.4 Các Collections Đối với nhiều ứng dụng, ta muốn tạo quản lý nhóm đối tượng liên quan Có hai cách để nhóm đối tượng: cách tạo mảng đối tượng cách tạo tập hợp đối tượng Mảng hữu ích để tạo làm việc với số lượng cố định đối tượng có kiểu Collection cung cấp cách linh hoạt để làm việc với nhóm đối tượng Khơng giống mảng, nhóm đối tượng mà ta làm việc mở rộng thu hẹp Học kết hợp Trang 11 LẬP TRÌNH NET cách linh hoạt nhu cầu ứng dụng thay đổi Đối với số collection, ta gán khóa cho đối tượng mà ta đưa vào collection để nhanh chóng truy xuất đối tượng cách sử dụng khóa Collection lớp, ta phải khai báo thể lớp trước ta thêm phần tử vào collection Nếu collection chứa phần tử kiểu liệu, ta sử dụng lớp namespace System.Collections.Generic Generic collection thực thi an tồn kiểu để khơng có kiểu liệu khác thêm vào Khi truy xuất phần tử từ Generic collection, ta xác định kiểu liệu chuyển đổi kiểu liệu cho 1.4.1 Sử dụng collection đơn giản Các ví dụ phần sử dụng lớp List, cho phép làm việc với danh sách đối tượng có chung kiểu liệu (T) Ví dụ 2.19: Ví dụ sau tạo danh sách chuỗi sau lặp qua chuỗi cách sử dụng câu lệnh foreach // Create a list of strings using System.Collections.Generic; using System; var salmons = new List(); salmons.Add("chinook"); salmons.Add("coho"); salmons.Add("pink"); salmons.Add("sockeye"); // Iterate through the list foreach (var salmon in salmons) { Console.Write(salmon + " "); } // Output: chinook coho pink sockeye Nếu nội dung collection biết trước, ta sử dụng collection constructor để khởi tạo collection Ví dụ 2.20: Ví dụ sau giống với ví dụ trước, ngoại trừ constructor sử dụng để thêm phần tử vào danh sách // Create a list of strings by using a // collection initializer using System.Collections.Generic; using System; var salmons = new List { "chinook", "coho", "pink", "sockeye" }; // Iterate through the list Học kết hợp Trang 12 LẬP TRÌNH NET foreach (var salmon in salmons) { Console.Write(salmon + " "); } // Output: chinook coho pink sockeye Có thể sử dụng câu lệnh for thay câu lệnh foreach để lặp qua danh sách Ta thực điều cách truy cập phần tử danh sách theo vị trí mục Chỉ số phần tử kết thúc số phần tử trừ Ví dụ 2.21: Ví dụ sau lặp lại qua phần tử danh sách cách sử dụng for thay foreach // Create a list of strings by using a // collection initializer using System.Collections.Generic; using System; var salmons = new List { "chinook", "coho", "pink", "sockeye" }; for (var index = 0; index < salmons.Count; index++) { Console.Write(salmons[index] + " "); } // Output: chinook coho pink sockeye Ví dụ 2.22: Ví dụ sau loại bỏ phần tử khỏi danh sách cách định đối tượng cần loại bỏ // Create a list of strings by using a // collection initializer using System.Collections.Generic; using System; var salmons = new List { "chinook", "coho", "pink", "sockeye" }; // Remove an element from the list by specifying // the object salmons.Remove("coho"); // Iterate through the list foreach (var salmon in salmons) { Console.Write(salmon + " "); } // Output: chinook pink sockeye Ta sử dụng phương thức RemoveAt() để loại bỏ phần tử danh sách theo vị trí danh sách Bảng liệt kê số phương thức thường dùng List: Phương thức Học kết hợp Chức Trang 13 LẬP TRÌNH NET Add( ) Thêm phần tử vào cuối List Insert( ) Thêm phần tử vào vị trí xác định Remove( ) Xóa phần tử lần xuất List RemoveAt( ) Xóa phần tử có số xác định Clear( ) Xóa tất phần tử khỏi List Contains() Kiểm tra phần tử có List khơng 1.4.2 Một số Generic collection khác Bảng liệt kê số collection khác nằm namespace Generic collection Người đọc tự tìm hiểu thêm qua nguồn tài liệu khác để vận dụng vào công việc Collection Mô tả Dictionary Represents a collection of key/value pairs that are organized based on the key List Represents a list of objects that can be accessed by index Provides methods to search, sort, and modify lists Queue Represents a first in, first out (FIFO) collection of objects SortedList Represents a collection of key/value pairs that are sorted by key based on the associated IComparer implementation Stack Represents a last in, first out (LIFO) collection of objects 1.5 Vào với file 1.5.1 Khái niệm file File gọi tập tin gọi tệp, khái niệm dùng để tập hợp thông tin liên quan với thông tin lưu trữ đĩa Khác với thông tin lưu trữ RAM, thông tin lưu file phải truy cập cách tuần tự, nghĩa muốn đọc ghi liệu vị trí thứ i xử lý phải thực việc đọc ghi từ vị trí đến vị trí i-1 Học kết hợp Trang 14 LẬP TRÌNH NET 1.5.2 Phân loại Tùy vào nội dung liệu chứa file, file chia thành loại: file nhị phân (binary file) file văn (text file) Trong phần giáo trình trình bày phương pháp đọc ghi file văn bản, người học tự nghiên cứu phương pháp đọc ghi file nhị phân từ tài liệu tham khảo phần tài liệu tham khảo cuối giáo trình File văn (text file) File văn file mà liệu ghi ký tự thuộc bảng mã ASCII chuẩn (bảng mã không bao gồm ký tự điều khiển) ký tự tổ chức thành nhiều hàng Các hàng phân cách ký tự xuống hàng Đối với file văn tổ chức hệ điều hành Dos Windows Microsoft hàng phân cách cặp ký tự bao gồm: ký tự xuống dòng ký tự đầu dòng Đối với file văn tổ chức hệ điều hành Unix Linux hàng phân cách dấu xuống hàng Điều giải thích người sử dụng mở số file vốn soạn thảo hệ điều hành Linux chương trình soạn thảo Windows (cụ thể notepad) tất dòng file nối thành dịng Các file văn thơng thường file văn đơn giản file mã nguồn ngơn ngữ lập trình file sở liệu XML File nhị phân (binary file) File nhị phân file mà thông tin lưu trữ cách tổng quát Dữ liệu lưu trữ file nhị phân chia thành byte, byte đặc trưng ký tự bảng mã ASCII mở rộng Các file nhị phân thường có cấu trúc định dạng riêng, file biên soạn theo định dạng có phần mềm hiểu định dạng đọc Ví dụ file hình ảng đọc chương trình hiển thị hình ảnh Các chương trình soạn thảo cho file văn khơng hiển thị xác file nhị phân Cụ thể người sử dụng dùng chương trình soạn thảo văn để mở file thực thi (.exe) chương trình soạn thảo văn hiển thị ký tự đặc biệt Các file nhị phân thông thường file thực thi (.exe), file hình ảnh (.jpg, gif, png, bmp, …), file âm (.mp3, wma, mid, wav, …), file chứa đoạn phim (.mpg, wmv, rm, …) nhiều dạng định dạng mặc định khác 1.5.3 Đọc ghi file văn Visual Studio cung cấp nhiều đối tượng để thực việc đọc ghi file văn Giáo trình trình bày việc đọc cặp đối tượng StreamReader StreamWriter Đây cặp đối tượng đọc/ghi tổng qt, người lập trình sử dụng cặp đối tượng để thực việc đọc ghi luồng nhập xuất khác Để sử dụng phương thức này, người lập trình phải khai báo sử dụng namespace System.IO Visual Studio lệnh using System.IO Học kết hợp Trang 15 LẬP TRÌNH NET Đọc file văn StreamReader StreamReader lớp lớp thực tạo đối tượng phục vụ việc đọc liệu từ luồng file Khi khởi tạo đối tượng, người lập trình phải cung cấp tên file cho phương thức khởi tạo Việc khởi tạo đối tượng sinh lỗi file không tồn tại, đĩa bị hỏng, …, đó, hàm khởi tạo phải đặt khối try/catch để xử lý ngoại lệ – Xử lý ngoại lệ trình bày chương Đối tượng StreamReader cung cấp nhiều phương pháp để đọc liệu, phương thức hữu hiệu phương thức ReadLine() Phương thức ReadLine() thực việc đọc dòng file văn trả chuỗi string Ví dụ 2.23: cho file văn có tên input.txt, file chứa số nguyên, số ngun nằm dịng Chương trình sau sử dụng đối tượng StreamReader để đọc file input.txt tính tổng số nguyên file Ghi file văn StreamWriter Cũng giống StreamReader, StreamWriter lớp lớp tạo đối tượng phục vụ việc ghi liệu vào luồng file Khi khởi tạo đối tượng, người lập trình phải cung cấp tên file cho phương thức khởi tạo Việc khởi tạo đối tượng sinh lỗi đĩa bị hỏng lỗi nhập xuất, …, đó, hàm khởi tạo phải Học kết hợp Trang 16 LẬP TRÌNH NET đặt khối try/catch để xử lý ngoại lệ Đối tượng StreamWriter cung cấp nhiều phương pháp để ghi liệu, phương thức hữu hiệu phương thức Write() Phương thức Write() thực việc ghi chuỗi string vào file văn Ví dụ 2.24: Sau chạy chương trình, file văn thu sau: Phương thức 2.1 Khái niệm Phương thức (method) chuỗi câu lệnh đặt tên, nhằm thực tác vụ cụ thể Mỗi chương trình C# có lớp với phương thức Main Một phương thức có tham số khơng, trả không trả giá trị, thực thi cách gọi tên phương thức cung cấp đối số cần thiết Như vậy, để sử dụng phương thức C#, ta cần: • Định nghĩa phương thức • Gọi phương thức 2.2 Định nghĩa phương thức Khi định nghĩa phương thức, bản, ta khai báo phần tử cấu trúc Cú pháp để định nghĩa phương thức C# sau: (Danh_sách_tham_số) Học kết hợp Trang 17 LẬP TRÌNH NET { Phần thân phương thức } Dưới chi tiết phần tử phương thức: • Access Specifier: Quy định cách thức truy cập phương thức (private – phương thức gọi từ phương thức khác lớp; public: phương thức gọi từ bên lớp) • Kiểu_trả_về: Một phương thức trả giá trị Kiểu trả kiểu liệu giá trị mà phương thức trả Nếu phương thức khơng trả giá trị nào, kiểu trả void • Tên_phương_thức: Tên phương thức định danh phân biệt kiểu chữ Nó khơng thể giống định danh khác khai báo lớp • Danh_sách_tham_số: Danh sách tham số bao quanh dấu ngoặc đơn, tham số sử dụng để truyền nhận liệu từ phương thức Danh sách tham số liên quan tới kiểu, thứ tự, số tham số phương thức Các tham số tùy ý, tức phương thức khơng chứa tham số • Phần thân phương thức: Phần thân phương thức chứa tập hợp thị cần thiết để hoàn thành hoạt động yêu cầu Ví dụ 2.25: Đoạn mã sau minh họa phương thức nhận hai giá trị integer trả tổng hai số Nó có Access Specifier, truy cập từ bên lớp sử dụng Instance (sự thể hiện) lớp using System; namespace MethodDemo { class Test { // dinh nghia phuong thuc public static int Cong(int so1, int so2) { int tong = so1 + so2; return tong; } } } 2.3 Gọi phương thức Ta gọi phương thức cách sử dụng tên phương thức Ví dụ sau minh họa cách gọi phương thức C#: Học kết hợp Trang 18 LẬP TRÌNH NET Ví dụ 2.26: using System; namespace MethodDemo { class Test { // dinh nghia phuong thuc public int Cong(int so1, int so2) { int tong = so1 + so2; return tong; } static void Main(string[] args) { Console.WriteLine("Goi phuong thuc C#"); Console.WriteLine(" "); /* khai bao bien cuc bo */ int a = 15; int b = 20; int tong; Test n = new Test(); //goi phuong thuc Cong tong = n.Cong(a, b); Console.WriteLine("Tong cua {0} {1} la: {2}", a, b, tong); Console.ReadLine(); Console.ReadKey(); } } } Xử lý ngoại lệ 3.1 Chương trình lỗi Chương trình (theo quan điểm cơng nghệ thông tin) khái niệm dùng để tập hợp mệnh lệnh có trật tự mà dựa vào máy tính thi hành Q trình người soạn thảo tập hợp lệnh cho chương trình gọi lập trình Trong q trình lập trình, lý lý khác mà kết thu chương trình khơng mong muốn, tình khơng mong muốn gọi chung lỗi (error defect) Trong lĩnh vực lập trình, lỗi thường chia thành loại chính: lỗi tiền biên dịch (pre-compiled error) lỗi thực thi (runtimed error) Lỗi tiền biên dịch (pre-compiled error) lỗi xuất xây dựng chương trình trình biên dịch thơng báo q trình biên dịch từ ngơn ngữ lập trình sang ngơn ngữ máy ngôn ngữ trung gian Các lỗi thuộc dạng thông thường lỗi liên quan đến cú pháp, liên quan đến khai báo liệu liên quan câu lệnh vốn hỗ trợ sẵn Các lỗi tiền biên dịch thông thường không nghiêm trọng thường phát chỉnh sửa dễ dàng Một số IDE hỗ trợ việc kiểm tra lỗi tự động q trình soạn thảo điều làm cho lỗi cấu trúc giảm đáng kể Các IDE hỗ trợ tính bao gồm: Visual Studio (tất phiên bản), NetBean, Eclipse, Jbuilder, … Học kết hợp Trang 19 LẬP TRÌNH NET Lỗi thực thi (runtimed error) lỗi xảy chạy chương trình Đây dạng lỗi tiềm ẩn chương trình chạy đến trạng thái định sinh lỗi Các lỗi thuộc dạng nghiêm trọng khó khắc phục lúc đó, chương trình biên dịch sang mã máy mã trung gian Các lỗi thuộc dạng thường có nhiều nguyên nhân: thuật tốn, khơng tương thích hệ thống liệu giãn nở, người lập trình khơng lường hết tất trạng thái xảy chương trình Có vài ví dụ cụ thể cho lỗi dạng mà người lập trình thường gặp phải như: lỗi chuyển kiểu từ kiểu chuỗi ký tự sang kiểu số nguyên, lỗi truy xuất đến phần tử nằm mảng, lỗi kết nối cở sở liệu, … 3.2 Khái niệm ngoại lệ Ngoại lệ (Exception) khái niệm sử dụng ngôn ngữ lập trình bậc cao dùng để biến cố khơng mong đợi chạy chương trình Bản chất ngoại lệ lỗi xảy trình thực thi (runtimed error) Các ngơn ngữ lập trình bậc cao Java Net cung cấp chế xử lý ngoại lệ (gọi chế try/catch) đặc tả lớp đặc trưng cho dạng ngoại lệ mà chương trình thường gặp 3.3 Xử lý ngoại lệ (Exception Handling) 3.3.1 Cơ chế try/catch Cơ chế try/catch chế Visual Studio đưa để xử lý ngoại lệ Cơ chế lập trình theo cú pháp sau: try { } catch (loại_biệt_lệ tên) {} [finally {}] Các lệnh có nguy gây lỗi đặt khối try Các lệnh bao gồm lệnh chuyển đổi kiểu liệu (từ kiểu chuỗi sang kiểu số), lệnh liên quan đến nhập xuất chí tốn tử chia… Khi gặp lệnh gây lỗi khối try, chương trình thực thi triệu gọi lệnh khối catch tương ứng để thực thi Khối catch khối lệnh thực ứng xử có lỗi, khối này, thơng thường người lập trình thực việc hiển thị lỗi Khi xây dựng khối catch, phải khai báo loại ngoại lệ (Exception-type) Tất Exception-type lớp kế thừa từ lớp Exception Trong lớp có phương thức ToString(), phương thức dùng để hiển thị thông tin lỗi cho người sử dụng Với dạng câu lệnh có Exception-type tương ứng, người lập trình xem hướng dẫn chi tiết phương Học kết hợp Trang 20 LẬP TRÌNH NET thức hướng dẫn MSDN để chọn Exception-type tương ứng Trong trường hợp người lập trình không quan tâm đến loại ngoại lệ, người lập trình sử dụng dạng Exception cho tất ngoại lệ Phương thức ToString() thích hợp tự động triệu gọi dựa theo tính đa hình hướng đối tượng (Polymorphism) chương trình ln hiển thị nội dung lỗi cho dù tất dạng ngoại lệ khai báo chung Exception Khối lệnh finally dùng để chứa lệnh xử lý cuối Các lệnh khối lệnh tự động triệu gọi cho dù lệnh khối try có sinh lỗi hay khơng Người lập trình khơng thiết phải khai báo khối lệnh finally, vậy, khối lệnh hữu ích việc thu dọn rác giải phóng vùng nhớ Ví dụ 2.27: Tính bình phương số ngun nhập từ bàn phím Nếu liệu nhập vào khơng phải số ngun chương trình báo lỗi: Trong ví dụ trên, lệnh Convert.ToInt32() thực việc chuyển từ kiểu chuỗi ký tự sang kiểu số nguyên lệnh có khả sinh lỗi chuỗi ký tự nhập vào không định dạng số nguyên Khi xảy lỗi chương trình khơng chạy dịng tiếo theo khối try mà chuyển sang khối catch Trong khối catch, lệnh hiển thị lỗi thực Trong trường hợp liệu nhập vào định dạng kiểu số nguyên, chương trình chạy kết sau: Trong trường hợp liệu nhập vào không với định dạng số nguyên, chương trình báo lỗi hiển thị cụ thể lỗi hình: Học kết hợp Trang 21 LẬP TRÌNH NET Trong khối catch, lệnh e.ToString() thường gọi để hiển thị lỗi, lỗi hiển thị xác với nội dung lỗi dòng mã sinh lỗi Với chế xử lý lỗi này, người lập trình dễ dàng tìm lỗi chỉnh sửa phù hợp 3.3.2 Xử lý ngoại lệ lồng Trong trình lập trình, có số tình mà chương trình phải thực nhiều lệnh có khả gây lỗi liên tiếp Để nắm bắt lỗi cách xác, lập trình viên thường thực việc bắt lỗi theo bước, nghĩa xử lý ngoại lệ lệnh xong xử lý ngoại lệ lệnh Ví dụ 2.28: Tính số dư chia số nguyên x cho số nguyên y, hai số nguyên nhập từ bàn phím Trong ví dụ này, chương trình có hai lệnh có khả sinh lỗi Lệnh thứ lệnh chuyển kiểu thực việc chuyển từ kiểu chuỗi ký tự sang kiểu số thực, lệnh gây ngoại lệ chuỗi ký tự nhập vào không định dạng số thực Lệnh thứ hai lệnh thực phép chia lấy số dư (%), lệnh gây ngoại lệ số chia Học kết hợp Trang 22 LẬP TRÌNH NET Trong ví dụ trên, khối lệnh try/catch bên thực việc xử lý ngoại lệ chia số x cho số y để lấy số dư Nếu y = ngoại lệ tạo ra, ngoại lệ thuộc lớp DivideByZeroException Khối lệnh try/catch bên thực việc xử lý ngoại lệ chuyển kiểu từ kiểu số chuỗi ký tự sang kiểu số nguyên Trong trường hợp hai số nhập vào x, y có định dạng phù hợp y khác chương trình chạy cho kết đúng: Trong trường hợp hai số nhập vào có định dạng khơng phải số ngun ngoại lệ xử lý Khi chương trình thơng báo lỗi chương trình khơng tiếp tục chạy để thực phép toán chia: Học kết hợp Trang 23 LẬP TRÌNH NET Trong trường hợp hai số nhập vào định dạng số nguyên y có giá trị ngoại lệ xử lý Trong trường hợp phép chia lấy số dư khơng thực chương trình thơng báo lỗi: Với ví dụ trên, ta dễ dàng nhận thấy việc xử lý ngoại lệ lồng cách phân cấp làm cho chương trình chặt chẽ lỗi nắm bắt dễ dàng Với ngoại lệ thơng báo hình, người lập trình dễ dàng nhận thấy chỉnh sửa đoạn mã phù hợp Tuy nhiên, việc xử lý nhiều ngoại lệ lồng cách phân cấp làm cho mã nguồn chương trình thêm nặng nề, khối try/catch xuất nhiều lần lồng làm cho cấu trúc chương trình trở nên phức tạp 3.3.3 Xử lý ngoại lệ song song Như trình bày phần trên, có nhiều lệnh có khả gây ngoại lệ ta cần phải thực xử lý tất ngoại lệ Để xử lý ngoại lệ, ta thực việc sử dụng cấu trúc try/catch cách tuần tự: lệnh thực trước xử lý trước, sau đó, bên khối try, người lập trình sử dụng cấu trúc try/catch khác để xử lý ngoại lệ cho lệnh Cách làm xử lý tất ngoại lệ làm cho chương trình trở nên phức tạp phải sử dụng nhiều cấu trúc try/catch lồng Để tối ưu hóa mã lệnh làm cho chương trình thêm tường minh, thơng thường người lập trình thực việc xử lý ngoại lệ song song Xử lý ngoại lệ song song trình xử lý ngoại lệ có khối try lại có nhiều khối catch Tất lệnh cần thiết đặt khối try khối catch thực việc bắt ngoại lệ tương ứng Khi chạy chương trình, ứng với ngoại lệ tạo ra, chương trình thực thi Net Framework tự động tham chiếu đến khối catch có ngoại lệ tương ứng để gọi lệnh xử lý Ví dụ 2.29: Trình bày việc cải tiến ví dụ trên, ví dụ này, ngoại lệ xử lý cách sử dụng hai khối catch khác để bắt lấy ngoại lệ khác Kết chạy chương trình cải tiến hồn tồn giống với kết chạy ví dụ phần trên: Học kết hợp Trang 24 LẬP TRÌNH NET Học kết hợp Trang 25