Câu lệnh, Biểu thức và Toán tử.
- 15-11-2023
- Toanngo92
- 0 Comments
Câu lệnh giúp bạn xây dựng chương trình và các toán tử giúp thực hiện các phép tính và tính toán. Một câu lệnh có thể bao gồm các toán tử, biến của các loại dữ liệu khác nhau và biểu thức. Trong C#, biến của các loại dữ liệu có độ chính xác thấp có thể được chuyển đổi sang các loại dữ liệu có độ chính xác cao và ngược lại. Trong buổi này, bạn sẽ học cách:
- Định nghĩa và mô tả câu lệnh và biểu thức
- Giải thích các loại toán tử
- Giải thích quy trình thực hiện chuyển đổi dữ liệu trong C#
Mục lục
Câu Lệnh và Biểu Thức
Mỗi chương trình là một tập hợp các nhiệm vụ được thực hiện để đạt được chức năng toàn bộ của chương trình. Để thực hiện những nhiệm vụ đó, người lập trình cung cấp các chỉ thị. Những chỉ thị này được gọi là câu lệnh trong C#. Một câu lệnh trong C# có thể chứa các biểu thức đánh giá thành một giá trị.
Câu Lệnh – Định Nghĩa
Câu lệnh được xem là việc nhóm lôgic của các biến, toán tử và từ khóa C# thực hiện một công việc cụ thể. Ví dụ, dòng lệnh khởi tạo một biến bằng cách gán giá trị cho nó là một câu lệnh.
Trong C#, mỗi câu lệnh kết thúc bằng dấu chấm phẩy. Một chương trình C# chứa nhiều câu lệnh được nhóm trong các khối. Một khối là một đoạn mã được đặt trong dấu ngoặc nhọn. Ví dụ, tập hợp các câu lệnh được bao gồm trong phương thức Main()
của một chương trình C# là một khối.
Hình bên dưới hiển thị định nghĩa.
Ghi chú: Một phương thức trong C# tương đương với một hàm trong các ngôn ngữ lập trình trước đây như C và C++.
Câu Lệnh – Ứng Dụng
Câu lệnh được sử dụng để xác định nhiệm vụ đầu vào, quá trình và đầu ra của một chương trình. Câu lệnh có thể bao gồm:
- Loại dữ liệu
- Biến
- Toán Tử
- Hằng số
- Ký tự literal
- Từ khóa
- Ký tự chuỗi thoát (escape sequence)
Câu lệnh giúp bạn xây dựng một luồng logic trong chương trình. Với sự giúp đỡ của câu lệnh, bạn có thể:
- Khởi tạo biến và đối tượng
- Nhận đầu vào
- Gọi một phương thức của một lớp
- Thực hiện các phép tính
- Hiển thị đầu ra
Đoạn mã bên dưới là một ví dụ về một câu lệnh trong C#.
double radius = 14.60;
double area = Math.PI * radius * radius;
Dòng mã này là một ví dụ về một câu lệnh C#. Câu lệnh tính diện tích của hình tròn và lưu giá trị vào biến “area
“.
Mã bên dưới là một ví dụ về một khối câu lệnh trong C#.
int side = 10;
int height = 5;
double area = 0.5 * side * height;
Console.WriteLine("Area: " + area);
Những dòng mã này thể hiện một khối mã được đặt trong dấu ngoặc nhọn. Câu lệnh đầu tiên từ trên xuống sẽ được thực hiện trước, tiếp theo là câu lệnh tiếp theo và cứ tiếp tục như vậy.
Mã bên dưới là một ví dụ về các khối lệnh lồng nhau trong C#.
int side = 5;
int height = 10;
double area;
area = 0.5 * side * height;
Console.WriteLine(area);
Những dòng mã này thể hiện một khối mã khác được lồng trong một khối câu lệnh. Ba câu lệnh đầu tiên từ trên xuống sẽ được thực hiện theo thứ tự. Sau đó, dòng mã trong dấu ngoặc nhọn bên trong sẽ được thực hiện để tính diện tích. Việc thực hiện kết thúc tại câu lệnh cuối cùng trong khối mã hiển thị diện tích.
Loại Câu Lệnh
Các câu lệnh trong C# tương tự như các câu lệnh trong C và C++. Các câu lệnh trong C# được phân loại thành bảy loại theo chức năng mà chúng thực hiện. Các loại này bao gồm:
- Câu Lệnh Lựa Chọn (Selection Statements)
Một câu lệnh lựa chọn là một câu lệnh quyết định kiểm tra xem một điều kiện cụ thể có đúng hay sai không. Các từ khóa liên quan đến câu lệnh này bao gồm if
, else
, switch
và case
.
- Câu Lệnh Lặp (Iteration Statements)
Một câu lệnh lặp giúp bạn thực hiện lặp đi lặp lại một khối mã. Các từ khóa liên quan đến câu lệnh này bao gồm: do
, for
, foreach
và while
.
- Câu Lệnh Nhảy (Jump Statements)
Một câu lệnh nhảy giúp bạn chuyển dòng chảy từ một khối mã sang một khối mã khác trong chương trình. Các từ khóa liên quan đến câu lệnh này bao gồm: break
, continue
, default
, goto
, return
và yield
.
- Câu Lệnh Xử Lý Ngoại Lệ (Exception Handling Statements)
Một câu lệnh xử lý ngoại lệ quản lý các tình huống không mong muốn gây trở ngại cho việc thực hiện bình thường của chương trình. Ví dụ, nếu mã đang chia một số cho không, chương trình sẽ không thực hiện đúng. Để tránh tình huống này, bạn có thể sử dụng các câu lệnh xử lý ngoại lệ. Các từ khóa liên quan đến câu lệnh này bao gồm: throw
, try-catch
, try-finally
và try-catch-finally
.
- Câu Lệnh Checked và Unchecked
Các câu lệnh checked và unchecked quản lý tràn số trong các biểu thức số học. Tràn số xảy ra nếu giá trị kết quả lớn hơn phạm vi của kiểu dữ liệu biến đích. Câu lệnh checked dừng thực hiện chương trình trong khi câu lệnh unchecked gán dữ liệu rác cho biến đích. Các từ khóa liên quan đến các câu lệnh này là checked
và unchecked
.
- Câu Lệnh Fixed
Câu lệnh fixed được yêu cầu để báo cho bộ thu gom rác không di chuyển đối tượng đó trong quá trình thực thi. Các từ khóa liên quan đến câu lệnh này là fixed
và unsafe
.
- Câu Lệnh Lock
Câu lệnh lock giúp khóa các khối mã quan trọng. Điều này đảm bảo rằng không có quá trình hoặc luồng khác đang chạy trong bộ nhớ máy tính có thể làm phiền mã. Các câu lệnh này đảm bảo an toàn và chỉ hoạt động với các loại tham chiếu. Từ khóa liên quan đến câu lệnh này là lock.
Câu Lệnh Checked và Unchecked
Câu lệnh checked kiểm tra tràn số trong biểu thức số học. Ngược lại, câu lệnh unchecked không kiểm tra tràn số. Tràn số xảy ra nếu kết quả của biểu thức hoặc một khối mã lớn hơn phạm vi của kiểu dữ liệu biến đích. Điều này làm cho chương trình phát sinh một ngoại lệ mà lớp OverflowException
bắt được. Ngoại lệ là những lỗi thời gian chạy làm gián đoạn luồng thực thi bình thường của chương trình. Lớp System.Exception
được sử dụng để tạo ra một số lượng lớn các lớp ngoại lệ xử lý các loại ngoại lệ khác nhau.
Câu lệnh checked liên quan đến từ khóa checked
. Khi có tràn số học xảy ra, câu lệnh checked dừng thực hiện chương trình.
Câu lệnh checked tạo một ngữ cảnh checked cho một khối câu lệnh và có dạng sau đây:
checked-statement
checked block
Mã bên dưới tạo một lớp Addition với câu lệnh checked. Câu lệnh này sẽ ném một ngoại lệ tràn số học.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace HelloWorld260324
{
internal class ExamOverflowArimethic
{
public static void Main()
{
byte numOne = 255;
byte numTwo = 1;
byte result = 0;
try
{
// Đoạn mã này sẽ ném một ngoại lệ tràn số
checked
//unchecked
{
result = (byte)(numOne + numTwo);
}
}
catch (OverflowException ex)
{
Console.WriteLine("Overflow Exception occurred."+ex.Message);
}
Console.WriteLine("Result: " + result);
}
}
}
Trong đoan mã trên hai số, numOne và numTwo, được cộng lại. Các biến numOne và numTwo được khai báo là byte
và được gán giá trị là 255 và 1 tương ứng. Khi câu lệnh trong khối checked
được thực thi, nó sẽ tạo ra một lỗi vì kết quả của việc cộng hai số này là 256, quá lớn để lưu trữ trong biến byte. Điều này dẫn đến một tràn số học.
Hình bên dưới hiển thị thông báo lỗi được hiển thị sau khi thực thi đoạn mã trên.
Câu lệnh unchecked
liên quan đến từ khóa unchecked
. Câu lệnh unchecked
bỏ qua tràn số học và gán dữ liệu rác cho biến đích.
Một câu lệnh unchecked
tạo một ngữ cảnh unchecked
cho một khối câu lệnh và có dạng sau đây:
unchecked-statement
unchecked block
Đoạn mã bên dưới tạo một lớp Addition sử dụng câu lệnh unchecked.
using System;
class Addition
{
public static void Main()
{
byte numOne = 255;
byte numTwo = 1;
byte result = 0;
try
{
unchecked
{
result = (byte)(numOne + numTwo);
}
Console.WriteLine("Result: " + result);
}
catch (OverflowException ex)
{
Console.WriteLine(ex);
}
}
}
Trong đoạn mã trên, khi câu lệnh trong khối unchecked
được thực thi, tràn số học được bỏ qua bởi câu lệnh unchecked
và nó trả về một giá trị không mong muốn.
Các câu lệnh checked
và unchecked
tương tự như các toán tử checked
và unchecked
. Sự khác biệt duy nhất là các câu lệnh hoạt động trên các khối thay vì trên biểu thức.
Câu Lệnh Ở Mức Đỉnh
C# 9.0 đã giới thiệu nhiều tính năng mới và một trong số đó là câu lệnh ở mức đỉnh. Tính năng này chủ yếu hoạt động với C# 9.0 trong .NET 5.0 và phiên bản Visual Studio 2019.
Với các câu lệnh ở mức đỉnh, bạn có thể dễ dàng giảm độ dài của chương trình và loại bỏ các dòng mã không cần thiết. Điều này được giải thích bằng ví dụ trong đoạn mã bên dưới
using System;
namespace HelloWorld
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("I am Iron man");
}
}
}
Trong đoạn mã trên, dòng mã Console.WriteLine
(“I am Iron man”); là dòng mã sẽ thực hiện hành động và phần còn lại chỉ là mã nền.
Phương thức Main
hoạt động như là bộ điều khiển của một ứng dụng. Nó định nghĩa chức năng cơ bản của đối tượng.
Một trong những lợi ích của các câu lệnh ở mức đỉnh là cho phép lập trình mà không cần phải có một phương thức Main
. Một câu lệnh ở mức đỉnh có thể được thực hiện với từ khóa using
. Điều này có nghĩa là phần còn lại của phương thức Main
và mọi mã nền có thể được thay thế bằng một câu lệnh ở mức đỉnh có từ khóa using
.
Điều này được minh họa thông qua đoạn mã bên dưới.
using System;
Console.WriteLine("I am Iron man");
Trong đoạn mã trên, toàn bộ mã đã được giảm xuống chỉ còn hai dòng chỉ bằng cách sử dụng từ khóa using. Loại câu lệnh này được gọi là ‘câu lệnh ở mức đỉnh’. Trong C# 9.0, một câu lệnh ở mức đỉnh có thể loại bỏ khai báo lớp, phương thức Main
, khai báo args[]
, và nhiều hơn nữa. Trong quá trình biên dịch, trình biên dịch sẽ tự động tạo ra phương thức Main với một mảng chuỗi args[]
.
Các đặc điểm của câu lệnh ở mức đỉnh như sau:
- Phương Thức Chính Ngụ Ý (Implicit Entry Point Method):
- Mỗi ứng dụng C# luôn phải có một điểm vào chương trình. Điều này có nghĩa là một dự án chỉ có thể có một tệp tin với các câu lệnh ở mức đỉnh. Nếu bạn đặt các câu lệnh ở mức đỉnh trong nhiều tệp tin hơn một trong một dự án, điều này sẽ gây ra lỗi biên dịch như sau:
CS8802 Only one compilation unit can have top-level statements.
- Một dự án có thể có bất kỳ số lượng tệp mã nguồn bổ sung nào mà không có các câu lệnh ở mức đỉnh.
- Phương thức
Main
có thể được viết một cách rõ ràng, nhưng nó không thể hoạt động như một điểm vào. Trong trường hợp này, trình biên dịch sẽ phát ra cảnh báo sau: CS7022 The entry point of the program is global code: ignoring 'Main' entry point.
- Câu lệnh ở mức đỉnh cho phép người dùng viết các câu lệnh C# mà không cần tạo một lớp một cách rõ ràng. Không thể có các câu lệnh ở mức đỉnh phân tán qua hai lớp khác nhau.
- Để chọn điểm vào trong một dự án với các câu lệnh ở mức đỉnh, tùy chọn trình biên dịch chính không thể được sử dụng ngay cả khi dự án có một hoặc nhiều phương thức Main.
- Không Gian Tên và Định Nghĩa Kiểu (Namespace and Type Definition):
- Một tệp tin có chứa các câu lệnh ở mức đỉnh cũng có thể bao gồm các không gian tên và định nghĩa kiểu, nhưng chúng phải được đặt sau các câu lệnh ở mức đỉnh. Điều này được minh họa trong Mã bên dưới
using System;
var member = new Member(ID = 1, Name = "Tony", Occupation = "Superhero");
Console.WriteLine(member.ID);
public class Member
{
public int ID { get; set; }
public string Name { get; set; }
public string Occupation { get; set; }
}
Ở đây, dòng thứ hai là một câu lệnh ở mức đỉnh và chương trình bao gồm một khai báo và định nghĩa lớp sau câu lệnh ở mức đỉnh. Các câu lệnh ở mức đỉnh có thể hữu ích cho cả lập trình viên mới và những nhà phát triển chuyên nghiệp.
Biểu Diễn – Định Nghĩa
Biểu diễn được sử dụng để thao tác dữ liệu. Giống như trong toán học, biểu diễn trong các ngôn ngữ lập trình, bao gồm C#, được xây dựng từ các toán hạng và toán tử. Một câu lệnh biểu diễn trong C# kết thúc bằng dấu chấm phẩy (;)
Biểu diễn được sử dụng để:
- Tạo ra giá trị.
- Tạo ra kết quả từ một đánh giá.
- Làm thành phần của một biểu diễn hoặc một câu lệnh.
Mã bên dưới minh họa một ví dụ về biểu diễn.
SimpleInterest = principal * time * rate / 100;
eval = -25 + 6 - 78 * 5;
run++;
Trong hai dòng mã đầu tiên, kết quả của các câu lệnh được lưu trữ trong các biến SimpleInterest
và eval. Câu lệnh cuối cùng tăng giá trị của biến run
.
Sự Khác Biệt Giữa Câu Lệnh và Biểu Diễn
Có một số sự khác biệt cơ bản giữa câu lệnh và biểu diễn. Bảng bên dưới hiển thị những sự khác biệt này.
Câu Lệnh | Biểu Diễn |
Không nhất thiết phải trả về. Ví dụ, xem xét câu lệnh sau:int oddNum = 5; Câu lệnh chỉ lưu giá trị 5 vào biến oddNum . | Luôn đánh giá thành một giá trị. Ví dụ, xem xét biểu thức sau:100 * (25 * 10) Biểu thức đánh giá thành giá trị 2500. |
Câu lệnh được thực thi bởi trình biên dịch. | Biểu thức là một phần của các câu lệnh và được đánh giá bởi trình biên dịch. |
Toán Tử
Biểu diễn trong C# bao gồm một hoặc nhiều toán tử thực hiện một số thao tác trên các biến. Một thao tác là một hành động được thực hiện trên một hoặc nhiều giá trị được lưu trữ trong các biến để sửa đổi chúng hoặc tạo ra một giá trị mới. Do đó, một thao tác diễn ra với sự giúp đỡ của ít nhất một ký hiệu và một giá trị. Ký hiệu được gọi là toán tử và nó xác định loại hành động sẽ được thực hiện trên giá trị.
Một toán hạng có thể là một biểu thức phức tạp. Ví dụ, trong biểu diễn a + b
, toán tử + được sử dụng để kết hợp hai toán hạng a và b.
Loại Toán Tử
Toán tử được sử dụng để đơn giản hóa các biểu diễn. Trong C#, có một bộ toán tử được định nghĩa trước để thực hiện các loại thao tác khác nhau trên giá trị.
Có sáu loại toán tử chính được phân loại dựa trên hành động chúng thực hiện trên các giá trị.
- Toán tử số học
- Toán tử quan hệ
- Toán tử logic
- Toán tử điều kiện
- Toán tử tăng và giảm
- Toán tử gán
Toán tử Số học – Loại
Toán tử số học là các toán tử hai ngôi vì chúng hoạt động với hai toán hạng, với toán tử được đặt giữa hai toán hạng. Những toán tử này cho phép bạn thực hiện các phép tính trên dữ liệu số hoặc chuỗi.
Bảng bên dưới liệt kê các toán tử số học cùng với mô tả và ví dụ của mỗi loại.
Toán tử | Mô tả | Ví dụ |
+ (Cộng) | Thực hiện phép cộng. Nếu hai toán hạng là chuỗi, nó hoạt động như toán tử nối chuỗi và thêm một chuỗi vào cuối chuỗi khác. | 40 + 20 |
– (Trừ) | Thực hiện phép trừ. Nếu giá trị lớn hơn bị trừ từ giá trị nhỏ hơn, kết quả là một giá trị âm. | 100 - 47 |
* (Nhân) | Thực hiện phép nhân. | 67 * 46 |
/ (Chia) | Thực hiện phép chia. Toán tử chia toán hạng đầu tiên cho toán hạng thứ hai và đưa ra kết quả là số dư. | 12000 / 10 |
% (Chia lấy dư) | Thực hiện phép chia lấy dư. Toán tử chia lấy dư cho hai toán hạng và đưa ra phần dư của phép chia. | 100 % 33 |
Đoạn mã số bên dưới thể hiện cách sử dụng các toán tử số học.
int valueOne;
int valueTwo = 2;
int add = valueOne + valueTwo;
int sub = valueOne - valueTwo;
int mult = valueOne * valueTwo;
int div = valueOne / valueTwo;
int modu = valueOne % valueTwo;
Console.WriteLine("Addition: " + add);
Console.WriteLine("Subtraction: " + sub);
Console.WriteLine("Multiplication: " + mult);
Console.WriteLine("Division: " + div);
Console.WriteLine("Remainder: " + modu);
Đầu ra:
Addition 12
Subtraction 8
Multiplication 20
Division 5
Remainder 0
Toán tử Quan hệ
Toán tử quan hệ thực hiện so sánh giữa hai toán hạng và trả về một giá trị boolean, true hoặc false.
Bảng bên dưới liệt kê các toán tử quan hệ cùng với mô tả và ví dụ cho mỗi loại.
Toán tử | Mô tả |
== | Kiểm tra xem hai toán hạng có giống nhau hay không. |
!= | Kiểm tra sự khác biệt giữa hai toán hạng. |
> | Kiểm tra xem giá trị đầu tiên có lớn hơn giá trị thứ hai hay không. |
< | Kiểm tra xem giá trị đầu tiên có nhỏ hơn giá trị thứ hai hay không. |
>= | Kiểm tra xem giá trị đầu tiên có lớn hơn hoặc bằng giá trị thứ hai hay không. |
<= | Kiểm tra xem giá trị đầu tiên có nhỏ hơn hoặc bằng giá trị thứ hai hay không. |
Đoạn mã bên dưới thể hiện cách sử dụng các toán tử quan hệ.
int leftVal = 50;
int rightVal = 100;
Console.WriteLine("Equal: " + (leftVal == rightVal));
Console.WriteLine("Not Equal: " + (leftVal != rightVal));
Console.WriteLine("Greater: " + (leftVal > rightVal));
Console.WriteLine("Lesser: " + (leftVal < rightVal));
Console.WriteLine("Greater or Equal: " + (leftVal >= rightVal));
Console.WriteLine("Lesser or Equal: " + (leftVal <= rightVal));
Kết quả:
Equal: False
Not Equal: True
Greater: False
Lesser: True
Greater or Equal: False
Lesser or Equal: True
Toán tử Logic
Toán tử logic là các toán tử hai ngôi thực hiện các phép toán logic trên hai toán hạng và trả về một giá trị boolean. Trong C#, có hai loại toán tử logic, đó là boolean và bitwise.
- Toán tử Logic Boolean
Toán tử logic boolean thực hiện các phép toán logic boolean trên cả hai toán hạng và trả về một giá trị boolean. Chúng hỗ trợ hai loại toán tử logic boolean:
Bảng bên dưới liệt kê các toán tử logic boolean cùng với mô tả và một ví dụ cho mỗi loại.
Toán tử | Mô tả |
& (AND Boolean) | Trả về true nếu cả hai biểu thức được đánh giá là true. |
| (OR Boolean) | Trả về true nếu ít nhất một trong các biểu thức được đánh giá là true. |
^ (XOR Boolean) | Trả về true nếu chỉ một trong các biểu thức được đánh giá là true. Nếu cả hai biểu thức đều là true, toán tử trả về false. |
Đoạn mã bên dưới giải thích cách sử dụng toán tử OR Boolean.
if ((quantity > 2000) | (price < 10.5)) {
Console.WriteLine("You can buy more goods at a lower price");
}
Trong đoạn mã, toán tử OR Boolean kiểm tra cả hai biểu thức. Nếu một trong chúng được đánh giá là true, biểu thức hoàn chỉnh trả về true và câu lệnh trong khối được thực thi.
Đoạn mã bên dưới giải thích cách sử dụng toán tử AND Boolean.
if ((quantity == 2000) & (price == 10.5)) {
Console.WriteLine("The goods are correctly priced");
}
Trong đoạn mã, toán tử AND Boolean kiểm tra cả hai biểu thức. Nếu cả hai biểu thức đều đánh giá là true, biểu thức hoàn chỉnh trả về true và câu lệnh trong khối được thực thi.
Đoạn bên dưới giải thích cách sử dụng toán tử XOR Boolean. (Đoạn mã 14 không được cung cấp trong yêu cầu của bạn.)
if ((quantity == 2000) ^ (price == 10.5)) {
Console.WriteLine("You have to compromise between quantity and price");
}
Trong đoạn mã, toán tử XOR Boolean kiểm tra cả hai biểu thức. Nếu chỉ một trong chúng được đánh giá là true, biểu thức hoàn chỉnh trả về true và câu lệnh trong khối được thực thi. Nếu cả hai đều là true hoặc cả hai đều là false, biểu thức trả về false.
- Toán tử Logic Bitwise
Toán tử logic bitwise thực hiện các phép toán logic trên từng bit tương ứng của hai toán hạng. Bảng bên dưới liệt kê các toán tử logic bitwise cùng với mô tả và một ví dụ cho mỗi loại.
Toán tử | Mô tả |
& (Bitwise AND) | So sánh hai bit và trả về 1 nếu cả hai bit đều là 1, ngược lại trả về 0. |
| (Bitwise OR) | So sánh hai bit và trả về 1 nếu ít nhất một trong các bit là 1. |
^ (Bitwise XOR) | So sánh hai bit và trả về 1 nếu chỉ một trong các bit là 1. |
Đoạn mã bên dưới giải thích cách hoạt động của toán tử AND bitwise.
int result = 56 & 28; // (56 = 00111000 và 28 = 00011100)
Console.WriteLine(result);
Trong đoạn mã số 15, toán tử AND bitwise so sánh các bit tương ứng của hai toán hạng. Nó trả về 1 nếu cả hai bit ở vị trí đó đều là 1, ngược lại trả về 0. So sánh này được thực hiện trên từng bit riêng lẻ và kết quả của những so sánh này tạo thành một số nhị phân 8-bit. Số này tự động chuyển đổi thành số nguyên, và kết quả được hiển thị là “24”.
Hình bên dưới thể hiện các toán tử logic bitwise.
Đoạn mã bên dưới giải thích hoạt động của toán tử OR bao gồm từng bit.
int result = 56 | 28;
Console.WriteLine(result);
Toán tử OR bitwise so sánh các bit tương ứng của hai toán hạng. Nó trả về 1 nếu một trong các bit ở vị trí đó là 1, ngược lại trả về 0. So sánh này được thực hiện trên từng bit riêng lẻ và kết quả của những so sánh này tạo thành một số nhị phân 8-bit. Số này tự động chuyển đổi thành số nguyên, và kết quả được hiển thị là “60
“.
Đoạn mã bên dưới giải thích hoạt động của toán tử OR độc quyền theo bit.
int result = 56 ^ 28;
Console.WriteLine(result);
Toán tử XOR bitwise so sánh các bit tương ứng của hai toán hạng. Nó trả về 1 nếu chỉ một trong các bit ở vị trí đó là 1, ngược lại trả về 0. So sánh này được thực hiện trên từng bit riêng lẻ và kết quả của những so sánh này tạo thành một số nhị phân 8-bit. Số này tự động chuyển đổi thành số nguyên, và kết quả được hiển thị là “36
“.
Toán tử Điều kiện
Có hai loại toán tử điều kiện, toán tử AND điều kiện (&&) và toán tử OR điều kiện (||). Toán tử điều kiện tương tự như toán tử logic boolean nhưng có những sự khác biệt sau đây:
- Toán tử AND điều kiện đánh giá biểu thức thứ hai chỉ nếu biểu thức thứ nhất trả về true. Điều này là do toán tử này chỉ trả về true nếu cả hai biểu thức đều là true. Do đó, nếu biểu thức thứ nhất trả về false, kết quả của biểu thức thứ hai là không quan trọng.
- Toán tử OR điều kiện đánh giá biểu thức thứ hai chỉ nếu biểu thức thứ nhất trả về false. Điều này là do toán tử này chỉ trả về true nếu một trong hai biểu thức là true. Do đó, nếu biểu thức thứ nhất trả về true, kết quả của biểu thức thứ hai là không quan trọng.
Hình bên dưới thể hiện các toán tử điều kiện.
Đoạn mã bên dưới hiển thị việc sử dụng toán tử AND (&&
) có điều kiện.
int num = 0;
if (num >= 1 && num <= 10) {
Console.WriteLine("The number exists between 1 and 10");
}
else {
Console.WriteLine("The number does not exist between 1 and 10");
}
Trong đoạn mã, toán tử AND điều kiện kiểm tra biểu thức đầu tiên. Biểu thức đầu tiên trả về false, do đó, toán tử không kiểm tra biểu thức thứ hai. Toàn bộ biểu thức đánh giá là false, và câu lệnh trong khối else
được thực thi.
Kết quả:
The number does not exist between 1 and 10
Đoạn mã bên dưới hiển thị việc sử dụng toán tử OR (| |
) có điều kiện.
int num = -5;
if (num < 0 || num > 10) {
Console.WriteLine("The number does not exist between 1 and 10");
}
else {
Console.WriteLine("The number exists between 1 and 10");
}
Trong đoạn mã, toán tử OR điều kiện kiểm tra biểu thức đầu tiên. Biểu thức đầu tiên trả về true, do đó, toán tử không kiểm tra biểu thức thứ hai. Toàn bộ biểu thức đánh giá là true, và câu lệnh trong khối if được thực thi.
Kết quả:
The number does not exist between 1 and 10
Toán tử Tăng và Giảm
Hai phép tính phổ biến nhất được thực hiện trong lập trình là tăng và giảm giá trị của biến đi 1. Trong C#, toán tử tăng (++
) được sử dụng để tăng giá trị lên 1 trong khi toán tử giảm (--
) được sử dụng để giảm giá trị xuống 1. Nếu toán tử được đặt trước toán hạng, biểu thức được gọi là tăng hoặc giảm trước. Nếu toán tử được đặt sau toán hạng, biểu thức được gọi là tăng hoặc giảm sau.
Bảng bên dưới mô tả việc sử dụng các toán tử tăng và giảm giá trị giả sử giá trị của biến valueOne là 5.
Biểu thức | Kiểu | Kết quả |
valueTwo = ++ValueOne; | Pre-Increment | valueTwo = 6 |
valueTwo = valueOne++; | Post-Increment | valueTwo = 5 |
valueTwo = –valueOne; | Pre-Decrement | valueTwo = 4 |
valueTwo = valueOne–; | Post-Decrement | valueTwo = 5 |
Toán tử gán được sử dụng để gán giá trị của toán hạng bên phải cho toán hạng bên trái bằng toán tử bằng (=). Các toán tử gán được chia thành hai loại trong C#. Đây là:
- Toán tử gán đơn giản (Simple assignment operators): Toán tử gán đơn giản là =, được sử dụng để gán một giá trị hoặc kết quả của một biểu thức cho một biến.
- Toán tử gán kết hợp (Compound assignment operators): Các toán tử gán kết hợp được tạo ra bằng cách kết hợp toán tử gán đơn giản với các toán tử số học.
Bảng bên dưới thể hiện cách sử dụng các toán tử gán giả sử giá trị của biến valueOne là 10.
Biểu thức | Mô tả | Kết quả |
valueOne += 5 | valueOne = valueOne + 5 | 10 |
valueOne -= 5 | valueOne = valueOne – 5 | 5 |
valueOne *= 5 | valueOne = valueOne * 5 | 25 |
valueOne %= 5 | valueOne = valueOne % 5 | 0 |
valueOne /= 5 | valueOne = valueOne / 5 | 2 |
Đoạn mã bên dưới giải thích cách sử dụng các toán tử gán.
int valueOne = 0;
Console.WriteLine("Value1: " + valueOne);
valueOne += 4;
Console.WriteLine("Value1 += 4: " + valueOne);
valueOne -= 8;
Console.WriteLine("Value1 -= 8: " + valueOne);
valueOne *= 7;
Console.WriteLine("Value1 *= 7: " + valueOne);
valueOne /= 2;
Console.WriteLine("Value1 /= 2: " + valueOne);
Console.WriteLine("Value1 == Value2: " + (valueOne == valueTwo));
Kết quả:
Value1: 0
Value1 += 4: 4
Value1 -= 8: -4
Value1 *= 7: -28
Value1 /= 2: -14
Value1 == Value2: False
Lưu ý: Toán tử gán khác biệt với toán tử bằng (==). Điều này là do toán tử bằng trả về true nếu giá trị của cả hai toán hạng bằng nhau, ngược lại trả về false.
Thứ tự Ưu tiên và Liên kết
Các toán tử trong C# có các cấp độ ưu tiên cụ thể. Trình biên dịch C# thực hiện các toán tử theo thứ tự được định nghĩa bởi cấp độ ưu tiên của chúng. Ví dụ, toán tử nhân (*) có ưu tiên cao hơn so với toán tử cộng (+). Do đó, nếu một biểu thức bao gồm cả hai toán tử, phép nhân sẽ được thực hiện trước phép cộng. Ngoài ra, việc thực thi của biểu thức (liên kết) có thể là từ trái sang phải hoặc ngược lại tùy thuộc vào các toán tử được sử dụng.
Bảng bên dưới liệt kê thứ tự ưu tiên của các toán tử, từ cấp độ ưu tiên cao nhất đến thấp nhất, mô tả của chúng và liên kết của chúng.
Cấp độ Ưu tiên | Toán tử | Mô tả | Liên kết |
1 | () | Dấu ngoặc đơn | Trái qua Phải |
2 | ++ hoặc — | Tăng hoặc giảm | Phải qua Trái |
3 | *, / , % | Nhân, chia, mô đun | Trái qua Phải |
4 | +, – | Cộng, trừ | Trái qua Phải |
5 | <, <=, >, >= | Nhỏ hơn, Nhỏ hơn hoặc bằng, Lớn hơn, Lớn hơn hoặc bằng | Trái qua Phải |
6 | =, != | Bằng, không bằng | Trái qua Phải |
7 | && | Điều kiện VÀ | Trái qua Phải |
8 | || | Điều kiện HOẶC | Trái qua Phải |
9 | =, +=, -=, *=, /=, %= | Toán tử gán | Phải qua Trái |
Đoạn mã bên dưới trình bày cách sử dụng các toán tử logic.
int valueOne = 10;
Console.WriteLine((4 * 5 - 3) / 6 + 7 - 8 % 5);
Console.WriteLine((32 < 4) || (8==8));
Console.WriteLine(((valueOne *=6) > (valueOne +=5)) && ((valueOne/=2) != (valueOne -=5)));
Trong đoạn mã, biến valueOne được khởi tạo với giá trị 10. Ba câu lệnh tiếp theo hiển thị kết quả của các biểu thức. Biểu thức được đưa trong dấu ngoặc đơn được giải quyết trước.
Kết quả:
6
True
False
Toán tử Dịch chuyển
Các toán tử dịch chuyển cho phép người lập trình thực hiện các thao tác dịch chuyển bit. Hai toán tử dịch chuyển là toán tử dịch chuyển sang trái (<<) và toán tử dịch chuyển sang phải (>>). Toán tử dịch chuyển sang trái cho phép dịch chuyển các vị trí bit về phía bên trái, trong đó bit cuối cùng bị cắt bỏ và số 0 được thêm vào bên phải. Toán tử dịch chuyển sang phải cho phép dịch chuyển các vị trí bit về phía bên phải và số 0 được thêm vào bên trái.
Đoạn mã bên dưới trình bày cách sử dụng toán tử dịch chuyển.
using System;
class ShiftOperator {
static void Main(string[] args) {
int num = 100; // 01100100 ~ 100
int result = num << 1; // 11001000 ~ 200
Console.WriteLine("Value before left shift: " + num);
Console.WriteLine("Value after left shift: " + result);
num = 80; // 10100000
result = num >> 1; // 11010000 ~ 40
Console.WriteLine("\nValue before right shift: " + num);
Console.WriteLine("Value after right shift: " + result);
}
}
Kết quả của đoạn mã trên được hiển thị trong Hình bên dưới
Trong Đoạn mã trên, phương thức Main()
của lớp ShiftOperator
thực hiện các thao tác dịch chuyển. Phương thức Main()
khởi tạo biến num với giá trị 100. Sau khi dịch chuyển về bên trái, giá trị của num tăng gấp đôi. Bây giờ, biến num được khởi tạo với giá trị 80. Sau khi dịch chuyển về bên phải, giá trị của num giảm một nửa.
Toán tử Nối chuỗi
Toán tử số học (+) cho phép người lập trình cộng các giá trị số học. Tuy nhiên, nếu một hoặc nhiều toán hạng là ký tự hoặc chuỗi nhị phân, cột, hoặc sự kết hợp của chuỗi và tên cột thành một biểu thức, thì toán tử nối chuỗi sẽ nối chúng. Nói cách khác, toán tử số học (+) được quá tải cho các giá trị chuỗi.
Mã bên dưới thể hiện việc sử dụng toán tử nối chuỗi.
using System;
class Concatenation {
static void Main(string[] args) {
int num = 4;
string msg = "";
if (num < 0) {
msg = "Số "+ num +" là số âm";
} else if (num % 2 == 0) {
msg = "Số "+ num +" là số chẵn";
} else {
msg = "Số "+ num +" là số lẻ";
}
if (msg != "") {
Console.WriteLine(msg);
}
}
}
Trong đoạn mã bên trên, phương thức Main()
của lớp Concatenation sử dụng cấu trúc if-else để kiểm tra xem một số có phải là số chẵn, số lẻ hay số âm không. Dựa vào điều kiện, mã hiển thị kết quả bằng cách sử dụng toán tử nối chuỗi (+) để ghép chuỗi với số.
Kết quả của đoạn mã trên thể hiện việc sử dụng toán tử nối chuỗi, như được hiển thị trong hình bên dưới.
Toán tử ba ngôi hoặc Toán tử điều kiện
Toán tử ?: được gọi là toán tử điều kiện. Thông thường, nó được sử dụng để thay thế các cấu trúc điều kiện if-else
. Vì nó yêu cầu ba toán hạng, nó còn được gọi là toán tử ba ngôi. Biểu thức đầu tiên trả về một giá trị bool
và tùy thuộc vào giá trị trả về của biểu thức đầu tiên, biểu thức thứ hai hoặc thứ ba sẽ được đánh giá. Nếu biểu thức đầu tiên trả về giá trị true, biểu thức thứ hai sẽ được đánh giá, trong khi nếu biểu thức đầu tiên trả về giá trị false, biểu thức thứ ba sẽ được đánh giá.
Cú pháp:
<Expression 1> ? <Expression 2> : <Expression 3>
trong đó,
Expression 1
: Là một biểu thức bool.Expression 2
: Được đánh giá nếu biểu thức 1 trả về giá trị true.Expression 3
: Được đánh giá nếu biểu thức 1 trả về giá trị false.
Mã bên dưới thể hiện việc sử dụng toán tử ba ngôi.
using System;
class LargestNumber {
public static void Main() {
int numOne = 5;
int numTwo = 25;
int numThree;
int result = 0;
if (numOne > numTwo) {
result = (numOne > numThree) ? numOne : numThree;
} else {
result = (numTwo > numThree) ? numTwo : numThree;
}
if (result != 0) {
Console.WriteLine("{0} là số lớn nhất", result);
}
}
}
Trong mã bên trên, phương thức Main()
của lớp LargestNumber kiểm tra và hiển thị số lớn nhất trong ba số numOne, numTwo, và numThree. Số lớn nhất này được lưu trong biến result. Nếu numOne lớn hơn numTwo, thì toán tử ba ngôi trong vòng lặp if được thực hiện.
Toán tử ba ngôi (?:) kiểm tra xem numOne có lớn hơn numThree hay không. Nếu điều kiện này đúng, thì biểu thức thứ hai của toán tử ba ngôi sẽ được thực hiện, gán numOne cho result. Nếu không, nếu numOne
không lớn hơn numThree
, thì biểu thức thứ ba của toán tử ba ngôi sẽ được thực hiện, gán numThree
cho result.
Phép so sánh tương tự được thực hiện để so sánh numOne và numTwo, và biến result
sẽ chứa giá trị lớn hơn trong hai giá trị này. Hình bên dưới thể hiện kết quả của ví dụ sử dụng toán tử ba ngôi.
Ép kiểu và các lợi ích
Hãy xem xét hệ thống tính lương của một tổ chức. Lương gộp của một nhân viên được tính toán và lưu trữ trong một biến kiểu float
. Hiện tại, kết quả được hiển thị dưới dạng giá trị float
. Phòng tính lương muốn số tiền lương là một số nguyên và do đó, muốn bỏ qua bất kỳ chữ số sau dấu thập phân của lương tính toán. Người lập trình có thể đạt được điều này bằng tính năng ép kiểu của C#. Ép kiểu cho phép bạn thay đổi kiểu dữ liệu của một biến.
C# hỗ trợ hai loại ép kiểu chính, được gọi là Ép kiểu Ngầm định và Ép kiểu Rõ Ràng. Ép kiểu chủ yếu được sử dụng để:
- Chuyển đổi một kiểu dữ liệu thành kiểu dữ liệu khác thuộc cùng một hoặc khác nhau. Ví dụ, cấu trúc thứ bậc số bao gồm
int
,float
vàdouble
. Bạn có thể chuyển đổi kiểuchar
thành kiểuint
để hiển thị giá trị ASCII. - Hiển thị kết quả số chính xác. Ví dụ, bạn có thể hiển thị phần dư chính xác trong các phép chia toán học.
- Ngăn mất mát dữ liệu số nếu giá trị kết quả vượt quá phạm vi của kiểu dữ liệu của biến.
Ép kiểu ngầm định cho các kiểu dữ liệu trong C# – Định nghĩa
Ép kiểu ngầm định đề cập đến việc chuyển đổi tự động của các kiểu dữ liệu. Điều này được thực hiện bởi trình biên dịch C#. Ép kiểu ngầm định chỉ xảy ra khi kiểu dữ liệu nguồn và đích thuộc cùng một thứ bậc. Ngoài ra, kiểu dữ liệu đích phải chứa một phạm vi giá trị lớn hơn so với kiểu dữ liệu nguồn. Ép kiểu ngầm định ngăn chặn việc mất mát dữ liệu vì kiểu dữ liệu đích luôn lớn hơn kiểu dữ liệu nguồn. Ví dụ, nếu bạn có một giá trị kiểu int
, bạn có thể gán giá trị đó cho biến kiểu long
.
Mã bên dưới thể hiện một ví dụ về ép kiểu ngầm định.
int valueOne = 34;
float valueTwo;
valueTwo = valueOne;
Trong đoạn mã trên, trình biên dịch tạo ra mã tự động chuyển đổi giá trị trong valueOne
thành một giá trị dạng số thực trước khi lưu kết quả vào valueTwo
. Việc chuyển đổi một giá trị số nguyên sang một giá trị số thực là an toàn.
Ghi chú: Ép kiểu trả về một giá trị theo kiểu dữ liệu đích mà không thay đổi giá trị của biến, mà là kiểu dữ liệu nguồn. Ép kiểu ngầm định còn được gọi là coercion.
Ép kiểu ngầm định cho các kiểu dữ liệu trong C# – Quy tắc
Ép kiểu ngầm định được thực hiện tự động bởi trình biên dịch. Trình biên dịch C# tự động chuyển đổi một kiểu dữ liệu có độ chính xác thấp hơn sang một kiểu dữ liệu có độ chính xác cao hơn khi biến đích có độ chính xác cao hơn so với biến nguồn. Hình bên dưới minh họa các kiểu dữ liệu có độ chính xác cao hơn mà chúng có thể được chuyển đổi.
Ép kiểu rõ ràng – Định nghĩa
Ép kiểu rõ ràng đề cập đến việc chuyển đổi một kiểu dữ liệu có độ chính xác cao hơn sang một kiểu dữ liệu có độ chính xác thấp hơn. Ví dụ, sử dụng ép kiểu rõ ràng, bạn có thể chuyển đổi giá trị của kiểu float
thành kiểu int
. Việc ép kiểu này có thể dẫn đến mất mát dữ liệu. Điều này xảy ra khi bạn chuyển đổi từ kiểu dữ liệu float
thành kiểu dữ liệu int
, các chữ số sau dấu thập phân sẽ bị mất.
Dưới đây là cú pháp cho việc chuyển đổi rõ ràng:
<target data type> <variable name> = (target data type)<source data type>;
Trong đó,
<target data type>
: Là kiểu dữ liệu kết quả.
<variable name>
: Là tên của biến, thuộc kiểu dữ liệu đích.
(target data type
): Là kiểu dữ liệu đích trong dấu ngoặc đơn.
<source data type
>: Là kiểu dữ liệu cần chuyển đổi.
Đoạn mã bên dưới hiển thị việc sử dụng chuyển đổi rõ ràng để tính diện tích hình vuông.
double side = 10.5;
int area;
area = (int)(side * side);
Console.WriteLine("Area of the square = {0}", area);
Kết quả:
Area of the square = 110
Ép kiểu rõ ràng – Thực hiện
Có hai cách để thực hiện ép kiểu rõ ràng trong C# bằng cách sử dụng các phương thức tích hợp sẵn. Các cách này bao gồm:
- Sử dụng lớp
System.Convert
: Lớp này cung cấp các phương thức hữu ích để chuyển đổi từ bất kỳ kiểu dữ liệu có sẵn nào sang kiểu dữ liệu khác. Ví dụ, phương thứcConvert.ToChar(Float)
chuyển đổi giá trịfloat
thành giá trịchar
.
- Phương thức
ToString()
: Phương thức này thuộc lớpObject
và chuyển đổi bất kỳ giá trị kiểu dữ liệu nào thànhstring
.
Đoạn mã bên dưới hiển thị giá trị float
dưới dạng chuỗi bằng phương thức ToString()
.
float floatNum = 500.25F;
string stNum = floatNum.ToString();
Console.WriteLine(stNum);
Trong đoạn code này, giá trị kiểu float được chuyển đổi thành kiểu string bằng phương thức ToString()
. Chuỗi được hiển thị trong cửa sổ console.
Kết quả:
500.25
Lưu ý: Lớp Object
là lớp cơ sở cho tất cả các loại giá trị được tạo trong C#.
Bài tập
Bài 01: Viết một chương trình C# in ra dãy số Fibonacci
Bài 02: Viết một chương tình C kiểm tra số nguyên tố.
Bài 03: Viết một chương trình C# tính giai thừa của một số bằng cách không sử dụng đệ quy và có sử dụng đệ quy.
Bài 04: Viết chương trình C# giải phương trình bậc 2: ax2 + bx + c = 0.
Bài 05: Viết chương trình C# tìm ước số chung lớn nhất (UCLN) và bội số chung nhỏ nhất (BCNN) của hai số a và b.
Bài 06: Viết chương trình C# liệt kê tất cả các số nguyên tố nhỏ hơn n.