Không gian tên là một định nghĩa mới trong ngôn ngữ máy tính, nhưng chúng rất hữu dụng, và một số có thể chứng minh rằng sự tồn tại của chúng là cần thiết. Một trong những vấn đề lớn nhất của lập trình là quá tải tên (name overlapping).
Câu lạc Khoa học - THPT Chuyên Lê Hồng Phong TPHCM LHPSC Lập trình C# Dịch từ sách Beginning C Sharp Game Programming Phần 4: C# Nâng cao Không gian tên (Namespace) Không gian tên định nghĩa ngơn ngữ máy tính, chúng hữu dụng, số chứng minh tồn chúng cần thiết Một vấn đề lớn lập trình tải tên (name overlapping) Hãy nói bạn tạo rừng lớp cho chương trình bạn, sau bạn muốn nhập thư viện người khác để giúp cho chương trình bạn Điều xảy số lớp người có tên với lớp bạn, làm việc khác nhau? Thật khơng may, điều xảy nhiều Lấy ví dụ, Direct3D DirectSound có lớp tên Device, bạn rõ ràng khơng thể có hai lớp có tên Khơng gian tên làm trở nên đơn giản, bạn ám thiết bị khác Direct3D.Device DirectSound.Device Bạn nghĩ khơng gian tên giống thành phố Nếu bạn nói với người bạn sống đường Nguyễn Văn Cừ (chẳng hạn), có đến hàng ngàn đường Nguyễn Văn Cừ đất nước Nếu muốn xác định xác bạn sống đâu, bạn cần phải nói với người thành phố bạn sống Tạo không gian tên giống việc cụ thể thành phố đường bạn mà đóbạn đặt số lớp (đường xá) bên khơng gian tên xác định (thành phố), chương trình bạn phân chia gọn gàng Bạn cho thứ vào khơng gian tên, bao gồm lớp, cấu trúc, trích xuất khơng gian tên khác! Hình 4.1 cho thấy ví dụ khơng gian tên Khơng gian tên System Không gian tên System.Data Không gian tên Chapter04 Lớp Chapter04.Spaceship Không gian tên System.Collections Lớp Chapter04.Spacesation Lớp System.Console Hình Đây hai khơng gian tên, System Chapter04 Trong không gian tên không gian tên lớp Lập trình C# - Phần 4: C# Nâng cao Trang Câu lạc Khoa học - THPT Chuyên Lê Hồng Phong TPHCM LHPSC Khơng gian tên tuyệt bạn phân cấp chúng – bạn cho nhiều khơng gian tên vào không gian tên tồn Ví dụ, NET framework bắt đầu với khơng gian tên System, với khơng gian tên khác nó, System.Data hay System.Collections Không gian tên phần cấp cho phép bạn tạo hệ thống phân cấp lớn hơn, giống Việt Nam tồn Đông Nam Á, Thành phố Hồ Chí Minh tồn Việt Nam, đường Nguyễn Văn Cừ tồn Thành phố Hồ Chí Minh Tạo Khơng gian tên Đây số mã mô tả việt sử dụng không gian tên: namespace Chapter04 { class Spaceship { // Mã }; class Spacestation { // Mã }; } Và sau đó, bên ngồi khơng gian tên, bạn truy cập lớp này: Chapter04.Spaceship s = new Chapter04.Spaceship(); Một tính khác khơng gian tên chúng phân chia thành nhiều phần Ví dụ, bạn có mã tập tin: namespace Chapter04 { class Spaceship // blah blah } sau cho trạm không gian vào tập tin khác: namespace Chapter04 { class Spacestation // blah blah } Trình dịch C# tự động ghép không gian tên cho bạn, bạn khơng phải cho tất vào tập tin lớn Sử dụng Không gian tên Khi bạn không gian tên, bạn sử dụng tất khơng gian tên mà khơng cần phải định danh Nếu bạn muốn truy cập lớp Spaceship bên lớp Spacestation ví dụ trước tơi cho bạn thấy, bạn cần đánh vào Spaceship C# cho bạn nói đến Chapter04.Spaceship bạn không gian tên Tuy nhiên, bạn ngồi khơng gian tên, bạn phải định danh khơng gian tên cách gõ Chapter04 phía trước Lập trình C# - Phần 4: C# Nâng cao Trang Câu lạc Khoa học - THPT Chuyên Lê Hồng Phong TPHCM LHPSC Đương nhiên, gõ Chapter04.Spaceship nhiều lần gây phiền toái lúc, đặc biệt bạn biết bạn sử dụng Spaceship Chapter04 nơi khác May mắn thay, bạn phép nói cho trình dịch C# bạn muốn sử dụng tất khơng gian tên đó, cách sử dụng từ khóa using Sử dụng này: // Ở phía mã nguồn: using Chapter04; // phía sau tập tin: Spaceship s = new Spaceship(); Ghi Từ khóa using đặt số nơi Từ khóa khơng thể đặt lớp, cấu trúc hay trích xuất, đặt gần chỗ khác Thực tế thường đặt đầu tập tin mã nguồn, bạn biết thư viện bạn cần tức Bí danh Khơng gian tên Khơng gian tên phân cấp gây phiền tối Có thể bạn chưa thấy điều đó, bạn sâu vào lập trình DirectX, bạn hét lên “Microsoft chết tiệt!” torng cổ họng bạn… trừ bạn biết bí danh cho không gian tên Mọi thứ liên quan đến Direct3D bên không gian tên Microsoft.DirectX.Direct3D Vậy bạn muốn truy cập thiết bị Direct3D, bạn phải gõ Microsoft.DirectX.Direct3D.Device, khơng? Thật may mắn, đặt bí danh cho không gian tên làm thứ tốt hơn! Về bạn, bạn lấy khơng gian tên nói với C# cho bí danh Đây bí danh cho khơng gian tên Direct3D: using D3D = Microsoft.DirectX.Direct3D; D3D.Device d; // thay cho: Microsoft.DirectX.Direct3D.Device d; Hãy xem, đặt bí danh cho khơng tên gian làm thứ đơn giản nào? Tính đa hình (Polymorphism) Chủ đề tính đa hình rộng phức tạp – trường đại học thường mở khóa học chủ đề Tơi cho bạn nhìn thống qua chủ đề Nhưng dù bạn không cần phải học q phức tạp tính đa hình Về ngơn ngữ, từ đa hình nghĩa “nhiều dạng” Trong ngơn ngữ máy tính, tính đa hình cho phép bạn tương tác với nhiều đối tượng khác mà không cần lo việc đối tượng thực Đâu ví dụ đời thực tính đa hình theo nghĩa ngơn ngữ máy tính, nghĩa xe Bạn vào xe, mở lên, đạp chân ga, bạn biết điều xảy ra: Chiếc xe bắt đầu chạy! Bây khỏi xe đó, vào xa hoàn toàn khác, làm tương tự: Chiếc xe bắt đầu chạy! Cá hai xa có chung giao diện (interface), bạn thực không cần quan tâm động hoạt động bên Cho dù bạn lái xe bốn xi lanh bình thường, xe đua tám xi lanh, hay xa điện, bạn biết đạp ga, xe bắt đầu Lập trình C# - Phần 4: C# Nâng cao Trang Câu lạc Khoa học - THPT Chuyên Lê Hồng Phong TPHCM LHPSC chạy Đây ví dụ tốt cho tính đa hình Máy vi tính gọi đối tượng làm việc, đối tượng đó, khơng quan tâm gì, làm việc Đa hình Hãy nói bạn có phân cấp bản: gốc hai Gốc Spaceship (tàu vũ trụ) CombatShip (tàu chiến) CargoShip (tàu chở hàng), hình 4.2 Hình Một phân cấp đơn giản Bạn chơi với chúng bình thường bạn làm: Spaceship s = new Spaceship(); CargoShip c = new CargoShip(); Đương nhiên, khơng có Nhưng điều đặc biệt CargoShip Spaceship cho phép bạn thực vài thủ thuật Nhìn dịng mã này: Spaceship s = new CargoShip(); Đoạn mã hồn tồn hợp lệ Dù sao, CargoShip SpaceShip, có nghĩa làm Spaceship trỏ tham chiếu tới CargoShip, khơng? Có giới hạn cho điều này: Tham chiếu SpaceShip không cho phép truy cập phần riêng lớp CargoShip mà khơng thừa kế từ SpaceShip Giả sử SpaceShip có hàm Refuel, CargoShip có hàm LoadCargo, nhìn vào đoạn mã ví dụ sau: Spaceship s = new CargoShip(); s.Refuel(); // ok // s.LoadCargo(); // LỖI BIÊN DỊCH SpaceShip không LoadCargo CargoShip c = (CargoShip)s; // vậy, chuyển thành CargoShip c.LoadCargo(); // ok Lập trình C# - Phần 4: C# Nâng cao Trang Câu lạc Khoa học - THPT Chuyên Lê Hồng Phong TPHCM LHPSC Bất kể mà bạn có tham chiếu đến lớp, bạn truy cập vào tính lớp xác định, đối tượng thực hỗ trợ nhiều tính Ghi Ghi bạn khơng thể sử dụng tính đa hình theo chiều ngược lại Nếu bạn cố gắng viết CargoShip c = new SpaceShip();, bạn có lỗi biên dịch Một SpaceShip CargoShip Hàm ảo (Virtual Function) Một khía cạnh quan trọng tính đa hình ý tưởng hàm ảo Một hàm ảo cho phép bạn định nghĩa hàm lớp ốc sau thay đổi Hãy nói này, tàu vũ trụ lo việc bị bắn laser cách khác nhau, bạn định nghĩa việc xử lý việc lớp SpaceShip gốc Sau đó, bạn đề nghị tàu chiến lo việc bị trúng đạn cách khác chúng có giáp tốt Hàm ảo cho phép bạn giải tình cách dễ dàng, bạn thấy mục sau Khi khơng có Hàm ảo Đây số mã làm rõ xảy ví dụ tơi mà khơng có hàm ảo: class Spaceship { public void LaserHit() { // Thiệt hại nhiều } } class CombatShip : Spaceship { public void LaserHit() { // Thiệt hại } } Điều mà vừa làm tạo lớp SpaceShip mặc định làm cho tàu bị nhiều thiệt hại bị trúng laser Tôi muốn CombatShip bị thiệt hại chúng có nhiều giáp hơn, tạo hàm LaserHit thực thiệt hại Đoạn mã làm xác bạn nghĩ là: Spaceship s = new Spaceship(); CombatShip c = new CombatShip(); s.LaserHit(); // Thiệt hại nhiều c.LaserHit(); // Thiệt hại Khơng có thủ thuật Nhưng mã sao? Spaceship s = Spaceship c = s.LaserHit(); c.LaserHit(); new Spaceship(); new CombatShip(); // Thiệt hại nhiều // Thiệt hại nhiều sao? Lập trình C# - Phần 4: C# Nâng cao Trang Câu lạc Khoa học - THPT Chuyên Lê Hồng Phong TPHCM LHPSC Điểm khác ? Thay sử dụng tham chiếu CombatShip ví dụ đầu tiên, lại sử dụng tham chiến SpaceShip thay vào đó, CombatShip lại bị thiệt hại giống SpaceShip bình thường? Lý hàm LaserHit SpaceShip không biến – vẩn Khi bạn gọi c.LaserHit(), gọi SpaceShip.LaserHit() biết c SpaceShip Vì trình biên dịch q ngu ngốc khơng nhận c thực CombatShip ngụy trang ? Đó cách mà trình biên dịch phải làm việc, bạn muốn thực theo cách mà bạn muốn thực hiện, bạn phải dùng tính ảo Chào mừng đến với tính Ảo Hàm ảo phát minh tuyệt vời Chúng không thực phức tạp Trước tơi giải thích chúng, để tơi thay đổi định nghĩa lớp SpaceShip CombatShip từ mục trước, để thêm vào vài từ khóa định nghĩa hàm : class SpaceShip { virtual public void LaserHit() { // Thiệt hại nhiều } } class CombatShip : Spaceship { override public void LaserHit() { // Thiệt hại } } Hai điểm nhỏ thay đổi: từ khóa virtual thêm hàm SpaceShip.LaserHit, override thêm vài CombatShip.LaserHit Bây giờ, bạn chạy mã này, làm xác bạn muốn: Spaceship s = Spaceship c = s.LaserHit(); c.LaserHit(); new Spaceship(); new CombatShip(); // Thiệt hại nhiều // Bây thiệt hại Hooray! Tại lại hoạt động? Khai báo hàm virtual nói với trình biên dịch hàm bị thay phiên khác lớp Nó nói: “Hey, hàm LaserHit hoạt động với tất SpaceShip đó, số SpaceShip sau thay đổi nó!.” Tương tự, khai báo hàm override nói với trình biên dịch hàm ghi đè lên phiên cũ Nó nói: “Hey, tơi biết hàm khai báo sớm rồi, phiên tốt nè, nên thay trước đó!” Ghi Nếu bạn khơng sử dụng từ khóa override khai báo CombatShip.LaserHit, bạn vào chung vấn đề trước Mọi CombatShip, xử lý SpaceShip, gọi SpaceShip.LaserHit thay hàm mà bạn muốn gọi Bạn phải khai báo rõ ràng hàm ghi đè lên phiên cũ Ngôn ngữ C++ Java không yêu cầu điều này, gây chút lầm lẫn với bạn lần Lập trình C# - Phần 4: C# Nâng cao Trang Câu lạc Khoa học - THPT Chuyên Lê Hồng Phong TPHCM LHPSC Ghi Từ khóa trái ngược với override từ khóa new Để trở lại với tình trạng ban đầu, bạn gõ new public void LaserHit() thay override public void LaserHit() Điều nàu ngăn SpaceShip chỗ phiên mới; phiên cũ gọi bạn làm việc với tham chiếu SpaceShip, phiên gọi bạn làm việc với tham chiếu CombatShip Trừu tượng (Abstraction) Bạn gặp tình mà bạn khơng biết hành vi mặc định lớp gốc Có thể bạn nhận câu nói “mọi tàu vủ trụ bị trúng laser theo cách này” cách nói ngu ngốc tàu vũ trụ khác dù nữa, bạn ghi đè hàm LaserHit lớp Vậy phải định nghĩa hàm Spaceship.LaserHit lần đầu tiên? Trong trường hợp này, bạn muốn sử dụng tính gọi trừu tượng Hàm Spaceship.LaserHit trừu tượng – bạn tàu bị trúng laser nào, bạn biết tàu bị trúng laser Nếu bạn đơn giản loại bỏ hàm LaserHit khỏi lớp Spaceship, bạn làm chuyện rói tung lên: Spaceship s = new CargoShip(); s.LaserHit(); // Lỗi! Spaceship bị trúng laser Thật may mắn, C# cho bạn cách để nói, “Mọi tàu vũ trụ biết trúng laser, tơi chưa chắn làm nào.” Đây định nghĩa lại lớp Spaceship: abstract class Spaceship { abstract public void LaserHit(); } Bây bạn có lớp Spaceship, bạn biết tất tàu vũ trụ bị trúng laser Điều ảnh hưởng nào? Liệu dịng mã sau có hợp lệ? Spaceship s = new Spaceship(); // Lỗi! Oops Bạn tạo Spaceship thêm Điều OK, bạn có lẽ khơng muốn làm điều – thay vào bạn có lẽ muốn tạo CombatShip CargoShip: Spaceship s1 = new CargoShip(); Spaceship s2 = new CombatShip(); s1.LaserHit(); s2.LaserHit(); Ghi Bạn làm nhanh lớp trừu tượng Hơn nữa, bạn có hàm trửu tượng lớp, lớp phải khai báo thành trừu tượng Ghi Bất kỳ hàm khai báo trừu tượng phải khai báo hàm ghi đè lớp Nếu bạn khơng làm điều này, bạn có lỗi biên dịch Lập trình C# - Phần 4: C# Nâng cao Trang Câu lạc Khoa học - THPT Chuyên Lê Hồng Phong TPHCM LHPSC Tính đa hình Hàm Tôi nghĩ têm ghi nhỏ việc sử dụng tính đa hình với thơng số hàm, trường hợp định nghĩa chưa thật rõ với bạ Hãy nói bạn tạo hàm làm việc với tất loại tàu vũ trụ Một số thứ này: class Foo { static void ProcessSpaceship( Spaceship s ) { // Một vài mã s.LaserHit(); } } Bạn turyền tàu chở hàng hay tàu chiến vào hàm khơng quan tâm đến loại tàu vũ trụ bạn gì: CargoShip cargo = new CargoShip(); CombatShip combat = new CombatShip(); Foo.ProcessSpaceship( cargo ); Foo.ProcessSpaceship( combat ); Hàm Foo.ProcessSpaceship không quan tâm đến loại tàu bạn dùng tất tàu có khả Đó sức mạnh tính đa hình Object Trong C#, có lớp tên object (đối tượng), nơi mà thứ thừa kế tự động Điều cho phép bạn lưu trữ liệu đối tượng chứa dễ dàng (bạn thấy mục sau phần này) Hãy nhìn đoạn mã này: object o = new CargoShip(); o = new int(); o = new float(); o = new WeebulCapacitorInfluxGasket(); Object lưu Sử dụng lớp object cách dễ dàng để biến kiểu giá trị - kiểu số dựng sẵn hay cấu trúc – thành kiểu tham chiếu Điều thực object sử dụng cách đóng gói kiểu giá trị Khi bạn cho kiểu giá trị vào object, object cấp phát nhớ cho kiểu giá trị đó, chép giá trị trỏ tới nhớ Hãy nhìn mã sau: int x = 10; object o = x; // o trỏ tới số nguyên 10 x = 20; // thay đổi x; o không thay đổi chép x = (int)o; // mở gói o, x lại 10 Đoạn mã cho bạn thấy để thực việc đóng gói mở gói Lập trình C# - Phần 4: C# Nâng cao Trang Câu lạc Khoa học - THPT Chuyên Lê Hồng Phong TPHCM LHPSC Ghi Bất kể bạn mở gói object, bạn phải gọi kiểu ban đầu cách rõ ràng (hay số kiểu liên quan, tương thích) Sự chuyển đổi ngầm khơng thể xảy Mảng (Array) Bạn biết đấy, thực tin phải học lâu đến phẩn mảng Tơi nói điều – C# thứ ngơn ngữ phức tạp Mảng hộp chứa cho phép bạn lưu trữ số đối tượng Cơ bản, bạn cần số cách để lưu trữ nhiều liệu, sử dụng biến bình thường để lưu tất trở nên tẻ nhạt cách nhanh chóng: Spaceship Spaceship Spaceship Spaceship Spaceship s1; // ok s2; // meh s3; // ok gây phiền phức chút s20; // ngón tay bắt đầu đau s42; // TRỜI ƠI DỪNG LẠI ĐI Thật kinh khủng lưu trữ liệu theo cách Đừng làm Khơng Hay tơi gửi sóc đến nhà bạn nhai dây điện máy vi tính bạn trước bạn nhấn nút Save, sau bạn dành 10 tiếng đồng hồ để đánh mã điên vớ vẩn bạn Thay phải làm tất thứ ngu ngốc thế, tạo mảng, khối liệu mà bạn truy cập số thứ tự Một ví dụ Mảng Đây ví dụ sử dụng mảng: int[] array = new int[10]; array[0] = 0; // phần tử array[1] = 10; // phần tử thứ hai 10 array[9] = 90; // phần tử cuối 90 Bây bạn có mười số nguyên, bạn truy cập chúng dễ dàng cách sử dụng ngoặc vuông sau tên mảng Ghi Mảng sử dụng đánh số từ không, tức phần tử mảng có số thay 1, theo nhiều người nghĩ Điều nghĩa mảng ví dụ trước có số hợp lệ từ đến 9, 10 không hợp lệ Mảng gì? Một mảng, tơi nói từ trước, khối liệu Khi bạn gõ mã sau, nói bạn tạo biến tên a, tham chiếu đến mảng số nguyên: int[] a; Tất mảng kiểu tham chiếu, có nghĩa bạn phải sử dụng từ khóa new để tạo mảng thực sự: Lập trình C# - Phần 4: C# Nâng cao Trang Câu lạc Khoa học - THPT Chuyên Lê Hồng Phong TPHCM LHPSC a= new int[8]; Dịng mã tạo mảng với tám số nguyên, cho thấy hình 4.3 Hình Hình cho thấy mảng gồm tám số nguyên Với tất ý đồ mục đích, bạn điều chỉnh a kiểm tham chiếu khác Đây số mã cho thấy bạn sử dụng mảng: int[] a = new int[10]; int[] b = a; b[0] = 10; int i = a[0]; b = null; a = new int[20]; object c = a; // // // // // // b trỏ đến mảng thay đổi b thay đổi a i 10 b khơng trỏ đến thứ mảng cũ bị mất, bị gom rác sau bạn tạo kiểu “object” Mảng dễ để sử dụng, bạn thấy Khởi tạo dịng Bạn khởi tạo giá trị trực tiếp cho mảng bạn tạo nó, sử dụng đoạn mã này: int[] array = new int[] { 1, 2, 3, 4, }; Mã tạo mảng số nguyên có năm phần tử, phần tử có giá trị 1, 2, 3, 4, Tham chiếu vs Giá trị Trong mục trước, cho bạn thấy mảng số nguyên, mà kiểu giá trị Điều đơn giản để hiểu Nhưng điều xảy bạn tạo mảng kiểu tham chiếu, Spaceship? Spaceship[] s = new Spaceship[5]; Điều có tạo mảng có năm tàu vũ trụ hay khơng? Khơng Nó thực tạo mảng có năm tham chiếu tàu vũ trụ Đoạn mã sau tạo tình mà hình 4.4 mơ tả Lập trình C# - Phần 4: C# Nâng cao Trang 10 Câu lạc Khoa học - THPT Chuyên Lê Hồng Phong TPHCM LHPSC Spaceship s = new Spaceship[5]; s[0] = new Spaceship(); s[2] = new Spaceship(); Hình 4 Một mảng tham chiếu, với số hợp lệ số null Phần tử trỏ tới tàu vũ trụ, phần tử cịn lại khơng trỏ vào đâu Bạn thấy mảng kiểu tham chiếu thực giữ tham chiếu, kiểu thực Bạn tạo đối tượng torng mảng tay bạn cần sử dụng chúng Như bạn học Phần 2, bạn sử dụng vịng lặp for để thực trình đơn giản Thừa kế Mảng Một điều tốt mảng chúng hỗ trợ hoàn toàn thừa kế Hãy nhìn vào đoạn mã ví dụ này: Spaceship[] s = new Spaceship[4]; s[0] = new CombatShip(); s[1] = new CargoShip(); s[2] = new CargoShip(); s[3] = new CombatShip(); for( int i = 0; i < 4; i++ ) s[i].LaserHit(); // bắn tàu Đoạn mã tạo mảng bốn tàu vũ trụ, điền vào hai tàu chở hảng hai tàu chiến Hai dòng cuối cho bạn thấy vòng lặp for lặp xuyên suốt mảng bắn laser vào tàu Điều hoạt động tốt trình biên dịch biết tất tàu vũ trụ biết làm bị trúng laser, khơng quan tâm đến tàu tàu chiến hay tàu chở hàng! Ghi Bạn dùng thuộc tính Length mảng để lấy số phần tử mảng bạn mảng rộng Lập trình C# - Phần 4: C# Nâng cao Trang 11 Câu lạc Khoa học - THPT Chuyên Lê Hồng Phong TPHCM LHPSC Mảng nhiều chiều Cho đến nay, tất tơi cho bạn thấy mảng chiều Nếu bạn biết hình học, bạn biết thứ mà có chiều có định nghĩa chiều dài; khơng có chiều rộng hay chiều cao Trong chiều, bạn vẽ đoạn thẳng Nó giống mảng: mảng chiều hình dung đoạn thẳng Nếu bạn dùng định nghĩa hình học mở rộng cho hai ba chiều, bạn tưởng tượng mảng nhìn giống hình 4.5 Chiều cao Chiều cao Chiều dài Chiều dài Chiều dài Hình Hình cho bạn thấy bố cục thị giác ba loại mảng khác Một mảng 2D nghĩ lưới vuông, bàn cờ Một mảng 3D nghĩ lưới lập phương, giống cục Rubik Bạn có mảng có nhiều chiều nữa, 4D, 5D, hay lên tới 32D, với nhiều người, hình dung chúng khó, chúng khơng sử dụng nhiều cho Cách đơn giản C# khác với C/C++/Java hỗ trợ mảng nhiều chiều Nếu bạn quen thuộc với ngơn ngữ này, điều khó chịu chút, thực khơng khó Về bản, để khai báo mảng 2D hay mảng 3D, bạn gõ này: int[,] array2d; int[,,] array3d; Và mảng 32D: int[,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,] array32d; Bạn đơn giản cần cho n-1 dấu phẩy vào dấu ngoặc vng để khai báo mảng n-chiều Lập trình C# - Phần 4: C# Nâng cao Trang 12 Câu lạc Khoa học - THPT Chuyên Lê Hồng Phong TPHCM LHPSC Bước tạo mảng thực sự: array2d = new int[5,5]; // mảng 5x5, hình 4.5 array3d = new int[5,5,3]; // mảng 5x5x3, hình 4.5 Bạn đổi số chiều để phù hợp với mục đích bạn Truy cập phần tử mảng đơn giản: array2d[0,0] = array2d[2,2] = array2d[0,4] = array3d[0,0,0] array3d[2,2,1] array3d[4,0,2] 100; // hình vng 200; // hình vng 300; // hình vng = 400; // khối hộp = 500; // khối hộp = 600; // khối hộp góc góc góc góc trái, nhìn hình 4.6 trái trái trước phải sau Cách khó khăn Có cách khác để tạo mảng, không dễ dàng cách cho bạn thấy Đây cách tiếp cận theo kiểu Java, thực khó khăn nhiều Cơ bản, ý tưởng mảng 2D mảng mảng 1D Nghe kỳ kỳ, khơng? Nhưng Hãy nhìn hình 4.6 để đối chiếu Hình Một cách vụng để tạo mảng 2D cách sử dụng mảng 1D để lưu trữ mảng 1D khác Một mảng lưu trữ thứ gì, khơng cho lưu mảng? Đây cách mà bạn khai báo mảng 2D mảng 3D theo kiểu này: int[][] array2d; int[][][] array3d; Lập trình C# - Phần 4: C# Nâng cao Trang 13 Câu lạc Khoa học - THPT Chuyên Lê Hồng Phong TPHCM LHPSC Tuy nhiên, cấp phát mảng cơng việc khó khăn Bạn khơng thể gõ số thứ này: int[][] array2d = new int[5][5]; // LỖI int[][][] array3d = new int[5][5][3]; // LỖI Trong ví dụ đầu tiên, tơi cố gắng cấp phét sáu mảng khác lần (một mảng cho mảng năm mảng cho số nguyên), C# không cho phép bạn làm Thay vào đó, bạn cần làm nhiều việc chút, cấp phát mảng cho mảng: int[][] array2d = new int[5][]; sau tạo mảng số nguyên riêng biệt: for( int i = 0; i < 5; i++ ) { array2d[i] = new int[5]; } Khi mà bạn xong, bạn bắt đầu điền liệu vào mảng: array2d[0][0] = 100; array2d[2][2] = 200; array2d[0][4] = 300; Đương nhiên, gây bừa bộn với mảng 3D bạn có mảng cho mảng cho mảng Vì vậy, bạn có khối việc để làm: int[][][] array3d = new int[5][][]; // Tạo chiều thứ hai mảng for( int i = 0; i < 5; i++ ) { array3d[i] = new int[5][]; } // tạo chiều thứ ba mảng for( int i = 0; i < 5; i++ ) { for( int j = 0; j < 5; j++ ) { array3d[i][j] = new int[3]; } } Bạn thu gọn mã bạn muốn, để đoạn mã bạn thấy rõ điều xảy Điều tơi ví dụ trước tạo mảng Vòng lặp xuyên điền vào năm phần tử mảng Đến bây giờ, tơi có mảng với phần tử, phần tử mảng có năm phần tử khác Và tơi có thứ nhìn giống hình 4.6 Vịng lặp cuối qua 25 phần tử mảng 2D điền vào mảng ba số nguyên Một đống lộn xộn lớn, không? Đó phương pháp tơi giới thiệu thơng dụng Lợi ích cách bạn khơng cần tạo mảng hình chữ nhật Ví dụ nhìn hình 4.8 Lập trình C# - Phần 4: C# Nâng cao Trang 14 Câu lạc Khoa học - THPT Chuyên Lê Hồng Phong TPHCM LHPSC Hình Sử dụng phương pháp này, bạn tạo mảng khơng có hình chữ nhật Từ bạn lưu trữ mảng mảng, mảng chiều cuối khơng cần có chung kích cỡ Điều hữu dụng số tình huống, tình khơng gặp q thường xuyên Một kiểu lặp khác Quay Phần 2, cho bạn thấy để thực vòng lặp khác C# cách sử dụng cấu trúc lặp for, while while Thực có vịng lặp C# tơi chưa nói đến: vịng lặp foreach Vịng lặp foreach thực dễ dàng để sử dụng cách đáng ngạc nhiên, dùng liệu (collection), mảng Ghi Vòng lặp foreach sử dụng cho liệu khác mà chưa cho bạn biết Tôi nói đến chúng Phần Đây cú pháp câu lệnh: foreach( kiểu biến in bộ_dữ_liệu ) { // Mã lặp } Câu lệnh qua đối tượng bên bộ_dữ_liệu với kiểu mà bạn định phần kiểu, bạn truy cập biến cách sử dụng biến Ví dụ: Lập trình C# - Phần 4: C# Nâng cao Trang 15 Câu lạc Khoa học - THPT Chuyên Lê Hồng Phong TPHCM LHPSC int[] array = new int[] { 1, 2, 3, 4, }; int sum = 0; foreach( int i in array ) { sum = sum + i; } Đoạn mã qua phần tử array cộng chúng lại Hạn chế vòng lặp foreach khơng cho phép thay đổi nội dung liệu mà hoạt động Nếu bạn có gắng tạo câu lệnh thay trước, bạn có lỗi biên dịch: foreach( int i in array ) { i = 0; } Đó trình biên dịch xử lý biến cách đọc, nên bạn thay đổi Thật khơng may, điều có nghĩa bạn đọc giá trị mảng kiểu giá trị, bạn thay đổi tham chiếu mảng kiểu tham chiếu Tuy nhiên, tin tốt bạn thay đổi kiểu tham chiếu thực, bạn có mảng lớp, bạn tiếp tục thay đổi lớp bạn muốn – bạn thay đổi số mảng đến lớp Chuỗi (String) Kể từ xa xưa, nhiều liên lạc thực nhờ văn Đó lý mà hầu hết ngơn ngữ lập trình có thư viện chuỗi tồn diện Khơng có ngạc nhiên, C# Thật may mắn chuỗi dễ sử dụng Nếu bạn sử dụng char*s C, bạn thích chuỗi C# Chúng làm cho việc sử dụng chuỗi thú vị! Hãy để vào cho bạn thấy số ví dụ: string str = “Hello!”; // “Hello!” str = str + “ How are you?”; // “Hello! How are you?” if( str == “Hello! How are you?” ) { str = “HI!”; // “HI!” } if( str != “HI!” ) { // điều kiện sai nên mã khơng cịn quan trọng } Chuỗi có tính chất độc đọc Bạn khơng thể thay đổi chúng, dù bạn cố gắng cỡ Nếu bạn muốn thay đổi chuỗi, bạn phải tạo chuỗi ghi đè lên (như dịng ví dụ trước) Lớp string, bên cạnh điều cho bạn thấy, hỗ trợ tất hàm hữu dụng: string str = “Hello”; string a; a = str.ToUpper(); // trả “HELLO” a = str.ToLower(); // trả “hello” a = str.Remove( 0, ); // trả “llo” Lập trình C# - Phần 4: C# Nâng cao Trang 16 Câu lạc Khoa học - THPT Chuyên Lê Hồng Phong TPHCM LHPSC a = str.Substring( 1, ); // trả “ell” Có hàng hàm vậy, hàm hữu dụng liệt kê bảng 4.1 Ghi biến str khơng thay đổi ví dụ trước, hàm trả chuỗi mới, thay thay đổi str Bảng 4.1 Hàm xử lý chuỗi hữu dụng Hàm bool Endswith( string ) string Insert( index, string) string PadLeft( width, fillchar ) string PadRight( width, fillchar ) string Remove( index, count ) string[] Spilt() bool Strartswith( string ) string Substring( index, count ) string string string string string ToUpper() ToLower() Trim() TrimEnd() TrimStart() Mô tả Xác định chuỗi có kết thúc string hay khơng Thêm string index Tăng độ dài chuỗi đến width, thêm vào số fillchars số khoảng cách bên trái Giống PadLeft, bên phải Bỏ count ký tự index Trả mảng tất từ chuỗi Xác định chuỗi có bắt đầu string hay khơng Trả lại chuỗi bắt đầy từ index có số ký tự count Chuyển ký tự thường thành hoa Chuyển ký tự hoa thành thường Cắt khoảng trắng trước sau chuỗi Cát khoảng trắng sau chuỗi Cắt khoảng trắng trước chuỗi Ghi Nếu bạn cần làm số thao tác phức tạp với chuỗi, thay dùng lớp string, bạn nên dùng System.Text.StringBuilder Thật khơng may nằm ngồi phạm vi sách Tôi muốn để bạn biết StringBuilder, cách hiệu quả để thực thao tác chuỗi phức tạp Một chuỗi mảng ký tự, mà tơi chờ để bạn biết mảng trước giới thiệu chuỗi cho bạn Bạn sử dụng chuỗi gần mảng truy cập vào ký tự riêng lẻ: string str = “hello!”; char c = str[0]; // ‘h’ c = str[3]; // ‘l’ Đương nhiên, chuỗi đọc, bạn thay đổi ký tự theo kiểu – bạn phải tạo chuỗi Nó phiền phức, điều khơng thể thay đổi Lập trình C# - Phần 4: C# Nâng cao Trang 17 ... array32d; Bạn đơn giản cần cho n-1 dấu phẩy vào dấu ngoặc vuông để khai báo mảng n-chiều Lập trình C# - Phần 4: C# Nâng cao Trang 12 Câu lạc Khoa học - THPT Chuyên Lê Hồng Phong TPHCM LHPSC Bước... rõ ràng hàm ghi đè lên phiên cũ Ngôn ngữ C++ Java không u cầu điều này, gây chút lầm lẫn với bạn lần Lập trình C# - Phần 4: C# Nâng cao Trang Câu lạc Khoa học - THPT Chuyên Lê Hồng Phong TPHCM... CombatShip(); // Thiệt hại nhiều // Thiệt hại nhiều sao? Lập trình C# - Phần 4: C# Nâng cao Trang Câu lạc Khoa học - THPT Chuyên Lê Hồng Phong TPHCM LHPSC Điểm khác ? Thay sử dụng tham chiếu