Dừng màn hình console trong c++

Và ᴄó, bất kỳ ᴠiệᴄ ѕử dụng ѕуѕtem() nào ᴄũng dẫn đến mã không thể truу ᴄập đượᴄ, ᴠì tham ѕố đượᴄ truуền ᴄho Shell ѕở hữu quу trình ᴄủa bạn.

Có mã tạm dừng trong mã nguồn ᴄủa bạn ѕớm haу muộn ᴄũng gâу ra rắᴄ rối:

ai đó quên хóa mã tạm dừng trướᴄ khi đăng ký bâу giờ tất ᴄả ᴄáᴄ bạn làm ᴠiệᴄ phải tự hỏi tại ѕao ứng dụng không đóng nữalịᴄh ѕử phiên bản bị ô nhiễm#define là địa ngụᴄnó gâу khó ᴄhịu ᴄho bất ᴄứ ai ᴄhạу mã ᴄủa bạn từ bảng điều khiểnthật là rất, rất, rất khó ᴄhịu khi ᴄố gắng bắt đầu ᴠà kết thúᴄ ᴄhương trình ᴄủa bạn từ trong một kịᴄh bản; khó ᴄhịu gấp bốn lần nếu ᴄhương trình ᴄủa bạn là một phần ᴄủa đường ống trong Shell, bởi ᴠì nếu ᴄhương trình không kết thúᴄ, tập lệnh Shell hoặᴄ đường ống ᴄũng ѕẽ không

Thaу ᴠào đó, hãу khám phá IDE ᴄủa bạn. Nó ᴄó thể ᴄó một tùу ᴄhọn không đóng ᴄửa ѕổ giao diện điều khiển ѕau khi ᴄhạу. Nếu không, đó là một lời biện minh tuуệt ᴠời ᴄho bạn ᴠới tư ᴄáᴄh là nhà phát triển đáng để ᴄô ấу/anh ấу luôn mở ᴄửa ѕổ giao diện điều khiển gần đó.

Ngoài ra, bạn ᴄó thể đặt tùу ᴄhọn ᴄhương trình nàу, nhưng ᴄá nhân tôi ᴄhưa bao giờ thấу ᴄhương trình ᴄó tùу ᴄhọn --keep-aliᴠe-ᴡhen-dead.

Đạo đứᴄ ᴄủa ᴄâu ᴄhuуện: Đâу là ᴠấn đề ᴄủa người dùng, ᴠà không phải ᴠấn đề ᴄủa ᴄhương trình. Đừng làm mờ mã ᴄủa bạn.

Xem thêm: Theme Wordpreѕѕ Hỗ Trợ Tiếng Việt, Hướng Dẫn Việt Hóa Webѕite Wordpreѕѕ


57
Cáᴄh tốt nhất để tạm dừng bàn điều khiển trong ᴄáᴄ ᴄhương trình C++ là gì?

ѕуѕtem("pauѕe"); ᴠà getᴄh(); (хuất phát từ thế giới DOS, IIRC) đều không thể truу ᴄập đượᴄ.

Có phải ᴄin.get () tốt hơn để ѕử dụng để tạm dừng bảng điều khiển? 

Là tùу ᴄhọn duу nhất di động ᴠà tiêu ᴄhuẩn , tôi ѕẽ nói ᴠậу, nhưng ᴄá nhân tôi tin rằng người ta không nên ᴠiết ᴄáᴄ ᴄhương trình bảng điều khiển tương táᴄ, tứᴄ là ᴄáᴄ ᴄhương trình thựᴄ ѕự tạm dừng bàn điều khiển hoặᴄ Nhắᴄ ᴄho đầu ᴠào (trừ khi ᴄó a thựᴄ ѕự lý do ᴄhính đáng ᴄho điều đó, bởi ᴠì điều đó làm ᴄho Shell ѕᴄripting khó hơn nhiều). Cáᴄ ᴄhương trình điều khiển nên tương táᴄ ᴠới người dùng thông qua ᴄáᴄ đối ѕố dòng lệnh (hoặᴄ ít nhất là loại tương táᴄ đó phải là tương táᴄ mặᴄ định).

Chỉ trong trường hợp bạn ᴄần tạm dừng ᴄhương trình ᴄho ᴄhương trình ᴄủa tôi đượᴄ khởi ᴄhạу-từ-IDE-ᴠà-ngaу-ѕau-đóng-nhưng-tôi-không-ᴄó-đủ-thời gian để хem lý do kết quả - không làm điều đó. Chỉ ᴄần định ᴄấu hình IDE hoặᴄ khởi ᴄhạу bàn điều khiển ᴄhương trình ngaу từ bảng điều khiển.


Không ᴄó ᴄáᴄh nào tốt để làm điều đó, nhưng bạn nên ѕử dụng giải pháp di động, ᴠì ᴠậу hãу tránh ᴄáᴄ ᴄuộᴄ gọi ѕуѕtem(), trong trường hợp ᴄủa bạn, bạn ᴄó thể ѕử dụng ᴄin.get() hoặᴄ getᴄh() như bạn đã đề ᴄập trong ᴄâu hỏi ᴄủa mình, ᴄũng ᴄó một lời khuуên. Thựᴄ hiện tất ᴄả tạm dừng đượᴄ kiểm ѕoát bởi một (hoặᴄ rất ít) định nghĩa tiền хử lý.

Ví dụ:

Một nơi nào đó trong tệp toàn ᴄầu:

#define USE_PAUSES#ifndef _DEBUG //I aѕume уou haᴠe _DEBUG definition for debug and don"t haᴠe it for releaѕe build#undef USE_PAUSES#endifMột nơi nào đó trong mã

#ifdef USE_PAUSESᴄin.get();#endifĐâу không phải là lời khuуên phổ biến, nhưng bạn nên tự bảo ᴠệ mình khỏi ᴠiệᴄ đặt tạm dừng trong ᴄáᴄ bản dựng phát hành ᴠà ᴄhúng nên đượᴄ kiểm ѕoát dễ dàng, tệp toàn ᴄầu đượᴄ đề ᴄập ᴄủa tôi ᴄó thể không quá toàn ᴄầu, ᴠì những thaу đổi trong đó ᴄó thể gâу ra rất lâu biên ѕoạn.

Giao diện console (console user interface, CUI), còn gọi là giao diện dòng lệnh (command line interface, CLI), là loại giao diện đơn giản nhất, trong đó dữ liệu xuất nhập đều là văn bản. Mặc dù không có gì hấp dẫn, ứng dụng với giao diện console (thường gọi tắt là ứng dụng console) luôn được sử dụng để dạy ngôn ngữ lập trình. Tương tự, trong khi học lập trình C# căn bản bạn sẽ gắn bó với ứng dụng console. Sự đơn giản của loại ứng dụng này giúp bạn tập trung vào các đặc trưng của ngôn ngữ, thay vì phân tâm cho sự phức tạp của giao diện đồ họa (Graphical User Interface) hay giao diện web.

Bài học này sẽ cung cấp cho bạn đầy đủ các kỹ thuật để làm việc với giao diện console trong C#: nhập, xuất, định dạng. Nắm chắc các kỹ thuật này sẽ giúp đơn giản hóa một phần việc học lập trình C# về sau.

NỘI DUNG CỦA BÀI

Giao diện console

Vai trò của ứng dụng console

Ứng dụng console là loại ứng dụng có giao diện đơn giản nhất, giúp người mới học lập trình tránh xa những sự phức tạp (chưa cần thiết) của các công nghệ GUI (Graphical User Interface – giao diện đồ họa).

Ứng dụng console sử dụng nhiều cho mục đích tính toán và xử lý, thay vì thể hiện dữ liệu. Nhiều chương trình tính toán nặng (trong khoa học) hay được viết bằng console thay vì dùng GUI. Các chương trình server thì hoàn toàn không cần đến GUI.

Ứng dụng console có hiệu suất cao và an toàn. Trên thực tế, rất nhiều ứng dụng dành cho quản trị hệ thống đều sử dụng giao diện console. Chắc bạn đã từng dùng Ping, IpConfig trên windows. Windows server còn có hẳn một giao diện dòng lệnh cao cấp (powershell) với hầu hết các công cụ đều thực hiện ở giao diện dòng lệnh. Nếu làm việc với Linux thì … thôi rồi, toàn chương trình console chạy trên shell.

Ứng dụng console không phụ thuộc quá chặt chẽ vào shell đồ họa của hệ thống và dễ dàng phục vụ đa nền tảng. Ví dụ, một ứng dụng console viết trên .NET framework (cho windows) có thể dễ dàng chạy tiếp trên Linux (Mono).

Các vấn đề của giao diện console trong C#

Vấn đề hiển nhiên nhất với ứng dụng console là việc xuất nhập dữ liệu. Mọi thứ xuất ra console đều là văn bản. Mọi thứ đọc vào từ console cũng đều là văn bản. Từ đây dẫn đến yêu cầu phải chuyển đổi kiểu dữ liệu khi xuất/nhập dữ liệu.

Vấn đề thứ hai là nhận lệnh và quyết định phương thức tương ứng nào sẽ được thực thi. Đối với các chương trình nhỏ thì đây không phải là vấn đề. Người mới học dễ dàng nghĩ tới sử dụng các cấu trúc rẽ nhánh để chọn phương thức phù hợp. Vậy nếu như có vài chục lệnh hoặc nhiều hơn nữa?

Vấn đề thứ ba là tham số đi kèm mỗi lệnh. Một lệnh người dùng nhập không thể thiếu tham số. Ví dụ lệnh “delete xyz.exe” có “xyz.exe” là tham số đi cùng lệnh. Làm thế nào để dễ dàng tiếp nhận, chuyển đổi và sử dụng tham số đó với lệnh?

Lớp System.Console

Trong C# lớp System.Console để thực hiện các công việc với giao diện console. Tất cả các thao tác quan trọng như xuất/nhập, định dạng dữ liệu xuất ra đều được thực hiện qua lớp này.

Dưới đây là một số thành viên của lớp Console:

  • Write(), WriteLine(): in thông tin ra console
  • Read(), ReadLine(), ReadKey(): đọc thông tin từ console
  • Beep(): phát tiếng bíp ra loa
  • BackgroundColor: đặt màu nền cho văn bản
  • ForegroundColor: đặt màu văn bản
  • Title: Đặt tiêu đề cho cửa sổ console
  • Clear(): xóa nội dung của console
  • BufferWidth/BufferHeight: đặt kích thước buffer cho console
  • WindowWidth/WindowHeight: đặt kích thước của console
  • WindowTop/WindowLeft: đặt vị trí của console

Xuất dữ liệu ra console trong C#: Write, WriteLine

Write và WriteLine

Để xuất dữ liệu ra giao diện console trong C# có thể sử dụng phương thức

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace P03_ColorfulConsole
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.Title = "Colorful Console";
            Console.ForegroundColor = ConsoleColor.Magenta;
            Console.Write("Your name: ");
            Console.ResetColor();
            var name = Console.ReadLine();
            Console.BackgroundColor = ConsoleColor.Blue;
            Console.Write(name);
            Console.ReadLine();
        }
    }
}
3 hoặc
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace P03_ColorfulConsole
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.Title = "Colorful Console";
            Console.ForegroundColor = ConsoleColor.Magenta;
            Console.Write("Your name: ");
            Console.ResetColor();
            var name = Console.ReadLine();
            Console.BackgroundColor = ConsoleColor.Blue;
            Console.Write(name);
            Console.ReadLine();
        }
    }
}
4. Hai phương thức này có thể nhận tham số thuộc bất kỳ kiểu nào, bất kỳ số lượng nào. Write hoặc WriteLine sau đó sẽ gọi tới phương thức
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace P03_ColorfulConsole
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.Title = "Colorful Console";
            Console.ForegroundColor = ConsoleColor.Magenta;
            Console.Write("Your name: ");
            Console.ResetColor();
            var name = Console.ReadLine();
            Console.BackgroundColor = ConsoleColor.Blue;
            Console.Write(name);
            Console.ReadLine();
        }
    }
}
5 của kiểu dữ liệu đó để chuyển tham số sang chuỗi ký tự và in ra console.

Lưu ý rằng, ToString() là phương thức được tất cả các kiểu kế thừa từ kiểu object (System.Object). Mỗi kiểu sẽ ghi đè ToString() theo cách riêng cho phù hợp. Bạn cũng có thể tự ghi đè phương thức này trong class do mình xây dựng.

WriteLine khác biệt với Write ở duy nhất một điểm: Sau khi in thông tin ra console, WriteLine sẽ xuống một dòng mới và di chuyển con trỏ văn bản về đầu dòng mới, trong khi Write giữ nguyên vị trí con trỏ ở sau ký tự cuối cùng được in ra.

Cùng thực hiện ví dụ đơn giản sau đây.

đặt tên là S04_Console. Console App đặt tên là P01_ConsoleOutput. Viết code cho Program.cs như sau:

using System;
namespace P01_ConsoleOutput
{
    class Program
    {
        static void Main()
        {
            Console.WriteLine(10); // in ra một số nguyên
            Console.WriteLine(10.0); // in ra một số thực
            Console.WriteLine(true); // in ra một giá trị logic
            Console.WriteLine("Hello world"); // in ra một chuỗi
            int a = 100;
            Console.WriteLine(a); // in ra một biến kiểu số nguyên
            bool b = false;
            Console.WriteLine(b); // in ra một biến kiểu logic
            string c = "Hi there!";
            Console.WriteLine(c); // in ra một biến kiểu xâu ký tự
            Console.ReadKey();
        }
    }
}
Dừng màn hình console trong c++
Dừng màn hình console trong c++

Bạn hãy tự thử thay WriteLine bằng Write trong ví dụ trên để thấy sự khác biệt.

Đối với các kiểu dữ liệu phức tạp (như class) thì phương thức 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace P03_ColorfulConsole
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.Title = "Colorful Console";
            Console.ForegroundColor = ConsoleColor.Magenta;
            Console.Write("Your name: ");
            Console.ResetColor();
            var name = Console.ReadLine();
            Console.BackgroundColor = ConsoleColor.Blue;
            Console.Write(name);
            Console.ReadLine();
        }
    }
}
6 chỉ đơn giản là in ra tên đầy đủ của kiểu dữ liệu mà không thể in ra các dữ liệu mà object đang chứa. Do đó, bạn cần tự mình ghi đè phương thức ToString() trên class mình xây dựng nếu muốn dùng trực tiếp với Write/WriteLine.

Thay đổi màu sắc cho console

Giao diện console nền đen chữ trắng không chỉ nhàm chán mà còn khó theo dõi khi hiển thị nhiều dữ liệu. Lớp Console cho phép thay đổi màu nền và màu văn bản in ra trên console thông qua thiết lập giá trị

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace P03_ColorfulConsole
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.Title = "Colorful Console";
            Console.ForegroundColor = ConsoleColor.Magenta;
            Console.Write("Your name: ");
            Console.ResetColor();
            var name = Console.ReadLine();
            Console.BackgroundColor = ConsoleColor.Blue;
            Console.Write(name);
            Console.ReadLine();
        }
    }
}
7 và
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace P03_ColorfulConsole
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.Title = "Colorful Console";
            Console.ForegroundColor = ConsoleColor.Magenta;
            Console.Write("Your name: ");
            Console.ResetColor();
            var name = Console.ReadLine();
            Console.BackgroundColor = ConsoleColor.Blue;
            Console.Write(name);
            Console.ReadLine();
        }
    }
}
8 trước khi gọi lệnh in Write hoặc WriteLine. Nếu muốn trả lại màu sắc mặc định chỉ cần gọi phương thức
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace P03_ColorfulConsole
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.Title = "Colorful Console";
            Console.ForegroundColor = ConsoleColor.Magenta;
            Console.Write("Your name: ");
            Console.ResetColor();
            var name = Console.ReadLine();
            Console.BackgroundColor = ConsoleColor.Blue;
            Console.Write(name);
            Console.ReadLine();
        }
    }
}
9.

Hãy cùng thực hiện ví dụ sau:

Thêm project P03_ColorfulConsole vào solution và viết code cho Program.cs:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace P03_ColorfulConsole
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.Title = "Colorful Console";
            Console.ForegroundColor = ConsoleColor.Magenta;
            Console.Write("Your name: ");
            Console.ResetColor();
            var name = Console.ReadLine();
            Console.BackgroundColor = ConsoleColor.Blue;
            Console.Write(name);
            Console.ReadLine();
        }
    }
}

Các hằng số màu được định nghĩa trong kiểu liệt kê (enum)

using System;
namespace P02_ReadLine
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.Write("Enter a number: ");
            string number = Console.ReadLine();            
            Console.WriteLine(number);
            Console.Write("Enter true or false: ");
            string logic = Console.ReadLine();            
            Console.WriteLine(logic);
            Console.Write("Enter a string: ");
            string message = Console.ReadLine();
            Console.WriteLine(message);
            Console.Write("Press enter to quit");
            Console.ReadLine(); // dừng màn hình chờ ấn enter
        }
    }
}
0 với 16 giá trị màu khác nhau. Một khi giá trị màu sắc đã được thiết lập nó sẽ có tác dụng đến khi gặp thiết lập màu khác, hoặc đến khi gặp ResetColor().

Trong ví dụ trên chúng ta cũng sử dụng property

using System;
namespace P02_ReadLine
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.Write("Enter a number: ");
            string number = Console.ReadLine();            
            Console.WriteLine(number);
            Console.Write("Enter true or false: ");
            string logic = Console.ReadLine();            
            Console.WriteLine(logic);
            Console.Write("Enter a string: ");
            string message = Console.ReadLine();
            Console.WriteLine(message);
            Console.Write("Press enter to quit");
            Console.ReadLine(); // dừng màn hình chờ ấn enter
        }
    }
}
1 để đặt tiêu đề cho cửa sổ console.

Nhập dữ liệu từ console trong C#: ReadLine, Read, ReadKey

So với xuất dữ liệu, việc đọc dữ liệu từ console phức tạp hơn một chút. Để nhập dữ liệu từ giao diện dòng lệnh có thể sử dụng các phương thức của lớp 

using System;
namespace P02_ReadLine
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.Write("Enter a number: ");
            string number = Console.ReadLine();            
            Console.WriteLine(number);
            Console.Write("Enter true or false: ");
            string logic = Console.ReadLine();            
            Console.WriteLine(logic);
            Console.Write("Enter a string: ");
            string message = Console.ReadLine();
            Console.WriteLine(message);
            Console.Write("Press enter to quit");
            Console.ReadLine(); // dừng màn hình chờ ấn enter
        }
    }
}
2, bao gồm 
using System;
namespace P02_ReadLine
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.Write("Enter a number: ");
            string number = Console.ReadLine();            
            Console.WriteLine(number);
            Console.Write("Enter true or false: ");
            string logic = Console.ReadLine();            
            Console.WriteLine(logic);
            Console.Write("Enter a string: ");
            string message = Console.ReadLine();
            Console.WriteLine(message);
            Console.Write("Press enter to quit");
            Console.ReadLine(); // dừng màn hình chờ ấn enter
        }
    }
}
3, 
using System;
namespace P02_ReadLine
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.Write("Enter a number: ");
            string number = Console.ReadLine();            
            Console.WriteLine(number);
            Console.Write("Enter true or false: ");
            string logic = Console.ReadLine();            
            Console.WriteLine(logic);
            Console.Write("Enter a string: ");
            string message = Console.ReadLine();
            Console.WriteLine(message);
            Console.Write("Press enter to quit");
            Console.ReadLine(); // dừng màn hình chờ ấn enter
        }
    }
}
4, 
using System;
namespace P02_ReadLine
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.Write("Enter a number: ");
            string number = Console.ReadLine();            
            Console.WriteLine(number);
            Console.Write("Enter true or false: ");
            string logic = Console.ReadLine();            
            Console.WriteLine(logic);
            Console.Write("Enter a string: ");
            string message = Console.ReadLine();
            Console.WriteLine(message);
            Console.Write("Press enter to quit");
            Console.ReadLine(); // dừng màn hình chờ ấn enter
        }
    }
}
5.

ReadLine

ReadLine đọc một dòng và trả về một chuỗi ký tự.

Khi sử dụng phương thức ReadLine, màn hình console sẽ dừng lại chờ nhập dữ liệu. Người dùng có thể nhập nhiều ký tự liên tục cho đến khi bấm phím Enter để kết thúc nhập.

Do ReadLine luôn trả về một chuỗi ký tự, chúng ta cần chuyển đổi chuỗi sang các kiểu khác theo nhu cầu.

Phương thức ReadLine cũng có thể dùng để dừng màn hình console chờ người dùng bấm Enter để tiếp tục.

Cùng thực hiện ví dụ sau. Tạo thêm project mới P02_ReadLine trong solution và viết code cho Program.cs:

using System;
namespace P02_ReadLine
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.Write("Enter a number: ");
            string number = Console.ReadLine();            
            Console.WriteLine(number);
            Console.Write("Enter true or false: ");
            string logic = Console.ReadLine();            
            Console.WriteLine(logic);
            Console.Write("Enter a string: ");
            string message = Console.ReadLine();
            Console.WriteLine(message);
            Console.Write("Press enter to quit");
            Console.ReadLine(); // dừng màn hình chờ ấn enter
        }
    }
}

ReadKey

ReadKey đọc một ký tự và trả về kiểu

using System;
namespace P02_ReadLine
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.Write("Enter a number: ");
            string number = Console.ReadLine();            
            Console.WriteLine(number);
            Console.Write("Enter true or false: ");
            string logic = Console.ReadLine();            
            Console.WriteLine(logic);
            Console.Write("Enter a string: ");
            string message = Console.ReadLine();
            Console.WriteLine(message);
            Console.Write("Press enter to quit");
            Console.ReadLine(); // dừng màn hình chờ ấn enter
        }
    }
}
6. Khi sử dụng ReadKey, màn hình console sẽ dừng lại chờ nhập dữ liệu.

Khi người dùng bấm một phím bất kỳ, ReadKey sẽ đọc và kết thúc nhập ngay lập tức (không cần dùng phím Enter để kết thúc nhập như ReadLine). Thông tin về ký tự người dùng đã nhập được trả về một biến thuộc kiểu ConsoleKeyInfo.

Phương thức ReadKey cũng thường được sử dụng để dừng màn hình console chờ người dùng bấm một phím bất kỳ để tiếp tục.

Thêm project P04_ReadKey vào solution và viết code cho Program.cs như sau:

using System;
namespace P04_ReadKey
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.Title = "ReadKey";
            Console.Write("Press any key: ");
            var key = Console.ReadKey();
            Console.WriteLine();
            Console.WriteLine(key.KeyChar);            
            Console.WriteLine(key.Modifiers);
            if (key.Key == ConsoleKey.H)
                Console.WriteLine("Hello!");
            Console.ReadKey();
        }
    }
}

Kiểu ConsoleKeyInfo lưu trữ một số thông tin về phím người dùng đã bấm:

  • KeyChar (kiểu char): ký tự người dùng đã nhập;
  • Modifiers (kiểu enum ConsoleModifiers): các phím điều khiển bấm cùng như Ctrl, Shift, Alt;
  • Key (kiểu enum ConsoleKey): phím chuẩn trên console.

ConsoleKey và char hoàn toàn không giống nhau, và cũng không thể sử dụng lẫn lộn nhau. Kiểu char bạn đã biết qua bài học các kiểu dữ liệu cơ sở của C#. Bạn có thể đọc thêm bài viết về ConsoleKey enum.

Read

Read đọc một ký tự và trả về mã của ký tự đó. Khi sử dụng Read, màn hình console sẽ dừng chờ nhập dữ liệu.

Người dùng có thể nhập cả một chuỗi ký tự và bấm phím Enter để kết thúc nhập. Tuy nhiên, Read chỉ trả về mã của ký tự đầu tiên của chuỗi người dùng nhập. 

Một số vấn đề khi làm việc với console trong C#

Đơn giản hóa lời gọi phương thức của Console

Từ C# 6 bắt đầu đưa vào cấu trúc using static để gọi tắt tới các thành viên static của một class. Lớp Console chứa toàn các thành viên static và rất phù hợp với cách dùng này. Hãy cùng làm lại ví dụ trên:

using System;
using static System.Console;
namespace P03_ColorfulConsole
{
    class Program
    {
        static void Main(string[] args)
        {
            Title = "Colorful Console";
            ForegroundColor = ConsoleColor.Magenta;
            Write("Your name: ");
            ResetColor();
            var name = ReadLine();
            BackgroundColor = ConsoleColor.Blue;
            Write(name);
            ReadLine();
        }
    }
}

Bạn đã bớt kha khá code với cách viết này khi không cần lặp lại tên class Console khi gọi phương thức hay thành viên tĩnh của nó nữa. Giờ đây nhìn code C# có gì đó na ná như Pascal 🙂

Biến đổi dữ liệu đọc từ console

Lấy ví dụ, bạn yêu cầu người dùng nhập vào một số nguyên. Do dữ liệu nhập từ console sử dụng ReadLine đều là string, bạn phải biến đổi chuỗi đó thành số thì mới sử dụng được trong biểu thức. Ngoài ra, do người dùng có thể vô tình nhập lẫn cả chữ cái vào chuỗi chữ số dẫn đến lỗi khi biến đổi.

Như vậy, khi đọc dữ liệu từ console bạn phải thực hiện hai nhiệm vụ: kiểm tra tính chính xác của chuỗi, biến đổi chuỗi về giá trị thuộc kiểu mình cần.

Hầu hết các kiểu dữ liệu cơ bản của C# đã hỗ trợ thực hiện các nhiệm vụ này với phương thức Parse() và TryParse(). Loại biến đổi dữ liệu này được gọi là type conversion, để phân biệt với type casting (ép kiểu).

Console.Write("Enter an integer: ");
string input = Console.ReadLine(); // đọc vào một chuỗi chữ số
int i = int.Parse(input); // biến đổi input thành int
Console.Write("Enter true or false: ");
input = Console.ReadLine(); // đọc chuỗi "true" hoặc "false"
bool b = bool.Parse(input); // biến đổi chuỗi thành bool
Console.Write("Enter a double: ");
input = Console.ReadLine(); // đọc vào một chuỗi chữ số
double d = double.Parse(input); // biến đổi input thành int

In chuỗi có định dạng với placeholder

Hãy cùng xem ví dụ sau đây:

int x1 = 123, x2 = 456;
Console.WriteLine("Nghiệm thứ nhất: {0}, Nghiệm thứ hai: {1}", x1, x2); 

Phương thức Write/WriteLine có thể in ra một xâu ký tự đồng thời ghép các biến vào những vị trí đánh dấu sẵn trong một xâu mẫu.

Trong ví dụ trên, vị trí đánh dấu (placeholder) được biểu diễn bằng cụm {0} và {1}. Trong đó {0} sẽ được thay thế bởi biến thứ nhất trong danh sách (tức là x1); {1} sẽ được thay thế bởi biến thứ hai trong danh sách (tức là x2).

Như vậy có thể để ý, các biến trong danh sách được đánh số thứ tự từ 0, và sẽ được thay thế vào vị trí đánh dấu có chỉ số tương ứng.

In chuỗi có định dạng với string interpolation

Bắt đầu từ C# 6 xuất hiện một phương pháp định dạng xâu mới gọi là interpolated.

Một xâu interpolated được bắt đầu bằng ký tự 

using System;
namespace P02_ReadLine
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.Write("Enter a number: ");
            string number = Console.ReadLine();            
            Console.WriteLine(number);
            Console.Write("Enter true or false: ");
            string logic = Console.ReadLine();            
            Console.WriteLine(logic);
            Console.Write("Enter a string: ");
            string message = Console.ReadLine();
            Console.WriteLine(message);
            Console.Write("Press enter to quit");
            Console.ReadLine(); // dừng màn hình chờ ấn enter
        }
    }
}
7, ở những vị trí cần thay thế bằng giá trị từ biểu thức/biến, biểu thức/biến đó sẽ đặt trong cặp dấu 
using System;
namespace P02_ReadLine
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.Write("Enter a number: ");
            string number = Console.ReadLine();            
            Console.WriteLine(number);
            Console.Write("Enter true or false: ");
            string logic = Console.ReadLine();            
            Console.WriteLine(logic);
            Console.Write("Enter a string: ");
            string message = Console.ReadLine();
            Console.WriteLine(message);
            Console.Write("Press enter to quit");
            Console.ReadLine(); // dừng màn hình chờ ấn enter
        }
    }
}
8.

Khi gặp loại xâu này, C# sẽ tính giá trị của biểu thức/lấy giá trị biến và đặt vào đúng vị trí quy định.

Ví dụ trên có thể viết lại theo cách mới như sau:

int x1 = 123, x2 = 456; 
Console.WriteLine($"Nghiệm thứ nhất: {x1}, Nghiệm thứ hai: {x2}");

Cách viết này rõ ràng, sáng sủa và dễ đọc hơn nhiều. Trong cặp dấu {} bạn có thể để bất kỳ biểu thức nào của C#, thậm chí cả những biểu thức phức tạp như phép toán điều kiện hay các đoạn code.

Định dạng số khi in ra console

Trong nhiều tình huống bạn cần in số có định dạng. Ví dụ khi in giá tiền, bạn muốn kèm theo đơn vị tiền tệ và chỉ với 2 chữ số thập phân. Bạn cũng có thể muốn dành một độ rộng cố định để in số (như trong bảng biểu). Bạn muốn số in ra căn lề trái hoặc căn lề phải.

Các lệnh in của Console hỗ trợ thực hiện các thao tác định dạng này. Định dạng in cho mỗi số bao gồm 3 phần: alignment, format và precision.

Để thử nghiệm, bạn hãy dùng C# Interactive.

Lưu ý: cách viết số này chỉ áp dụng được trong chuỗi có định dạng với placeholder hoặc string interpolation.

Format specifier

Ví dụ, để in ra giá tiền, bạn dùng :C hoặc :c phía sau chỉ số trong placeholder, hoặc sau tên biến trong interpolated string. Đơn vị tiền tệ sẽ phụ thuộc vào cấu hình ngôn ngữ của windows.

> Console.WriteLine("The value: {0}", 500)
The value: 500
> Console.WriteLine("The value: {0:C}", 500)
The value: $500.00
> Console.WriteLine("The value: {0:c}", 500)
The value: $500.00
> decimal value = 500;
. Console.WriteLine($"The value: {value:C}");
The value: $500.00
> Console.WriteLine($"The value: {value:c}");
The value: $500.00
> 

C hoặc c là định dạng số chuẩn dành cho kiểu tiền tệ (currency). Ngoài C (c), bạn có thể gặp thêm các trường hợp khác: D, d – Decimal; F, f – Fixed point; G, g – General; X, x – Hexadecimal; N, n – Number; P, p – Percent; R, r – Round-trip; E, e – Scientific.

Các ký tự định dạng số chuẩn này phải đi ngay dấu hai chấm, ví dụ :C, :c, :P, :p, như bạn đã thấy ở trên.

Bạn có thể tự mình thử nghiệm các định dạng trên để xem kết quả.

Precision specifier

Sau ký tự định dạng bạn có thể sử dụng thêm một con số để mô tả độ chính xác (Precision specifier) của giá trị được in ra.

Ví dụ, mặc định :C sẽ in ra hai chữ số thập phân. Bạn có thể yêu cầu in ra con số với độ chính xác cao hơn (3-4 chữ số thập phân) hoặc thấp hơn. Chẳng hạn :c3 chỉ định in ra 3 chữ số thập phân, :c4 chỉ định in 4 chữ số thập phân.

> Console.WriteLine($"The value: {value:c3}");
The value: $500.000
> Console.WriteLine($"The value: {value:c4}");
The value: $500.0000

Cách thể hiện của “độ chính xác” phụ thuộc vào loại số và định dạng của nó. Bạn hãy xem ví dụ sau đây:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace P03_ColorfulConsole
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.Title = "Colorful Console";
            Console.ForegroundColor = ConsoleColor.Magenta;
            Console.Write("Your name: ");
            Console.ResetColor();
            var name = Console.ReadLine();
            Console.BackgroundColor = ConsoleColor.Blue;
            Console.Write(name);
            Console.ReadLine();
        }
    }
}
0

Alignment specifier

Để dễ hiểu, hãy xem ví dụ sau:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace P03_ColorfulConsole
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.Title = "Colorful Console";
            Console.ForegroundColor = ConsoleColor.Magenta;
            Console.Write("Your name: ");
            Console.ResetColor();
            var name = Console.ReadLine();
            Console.BackgroundColor = ConsoleColor.Blue;
            Console.Write(name);
            Console.ReadLine();
        }
    }
}
1

Ở đây chúng ta mô phỏng lại việc in giá trị ra thành cột. Con số 10 và -10 viết tách với chỉ số placeholder bằng dấu phẩy được gọi là alignment specifier. Alignement specifier chỉ định độ rộng (số lượng ký tự) tối thiểu để in giá trị số đó. Giá trị dương báo hiệu căn lề phải; Giá trị âm báo hiệu căn lề trái.

Format specifier mà bạn đã biết viết về phía phải của alignment specifier:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace P03_ColorfulConsole
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.Title = "Colorful Console";
            Console.ForegroundColor = ConsoleColor.Magenta;
            Console.Write("Your name: ");
            Console.ResetColor();
            var name = Console.ReadLine();
            Console.BackgroundColor = ConsoleColor.Blue;
            Console.Write(name);
            Console.ReadLine();
        }
    }
}
2

Kết luận

Bài viết đã cung cấp cho bạn hầu hết những kiến thức cần thiết để làm việc với giao diện console trong C#. Từ giờ trở đi bạn đã có trong tay hai công cụ để chạy thử code: dùng C# Interactive hoặc viết chương trình Console App.

Các kỹ thuật làm việc với console trong bài học này sẽ còn đi cùng bạn đến cuối bài giảng này. Vì vậy hãy tự mình thử nghiệm thật nhiều với ứng dụng console cho thành thạo.