Back to blog

Giai Đoạn 1: C# Cơ Bản — Bắt Đầu với C#

csharpdotnetprogrammingfundamentalsbackend
Giai Đoạn 1: C# Cơ Bản — Bắt Đầu với C#

Chào Mừng Đến Giai Đoạn 1

Chào mừng đến với giai đoạn đầu tiên trong hành trình học C# của bạn! Nếu bạn đến từ Python, Java, JavaScript hay ngôn ngữ khác, bạn sẽ tìm thấy nhiều khái niệm quen thuộc ở đây — cùng với một số điểm thú vị. C# đã phát triển nhanh chóng, và C# hiện đại (phiên bản 10–12) là một ngôn ngữ thực sự thanh lịch.

Mục tiêu của giai đoạn này là giúp bạn quen với cú pháp C#, hiểu cách .NET tiếp cận các khái niệm lập trình cơ bản, và thiết lập môi trường phát triển hoạt động.

Đây không phải là hướng dẫn "biến là gì?". Chúng ta sẽ tập trung vào cú pháp đặc trưng của C#, hệ thống kiểu .NET, và các tính năng hiện đại phân biệt C# với các ngôn ngữ bạn đã biết.

Cam kết thời gian: 2 tuần, 1–2 giờ mỗi ngày
Điều kiện tiên quyết: Kinh nghiệm lập trình với bất kỳ ngôn ngữ nào

Bạn Sẽ Học Được Gì

Khi kết thúc Giai Đoạn 1, bạn sẽ có thể:

✅ Thiết lập môi trường phát triển .NET
✅ Viết và chạy chương trình C# với top-level statements
✅ Hiểu value types vs reference types của C#
✅ Sử dụng nullable reference types cho an toàn null
✅ Viết control flow với switch expressions và pattern matching hiện đại
✅ Định nghĩa methods với các modifier tham số khác nhau
✅ Làm việc với strings, string interpolation và raw string literals
✅ Tạo classes, records và properties cơ bản

Thiết Lập Môi Trường

1. Cài Đặt .NET SDK

Tải .NET SDK từ trang chính thức:

Khuyến nghị: .NET 8 LTS (Long-Term Support)

# Kiểm tra cài đặt
dotnet --version    # Nên hiển thị 8.x.x
 
# Liệt kê các SDK đã cài đặt
dotnet --list-sdks

Trên macOS với Homebrew:

brew install dotnet

Trên Linux (Ubuntu/Debian):

sudo apt-get update && sudo apt-get install -y dotnet-sdk-8.0

2. Chọn IDE

Visual Studio Code + C# Dev Kit (khuyến nghị cho đa nền tảng):

  • Miễn phí, nhẹ, hỗ trợ .NET xuất sắc
  • Cài extension: C# Dev Kit (Microsoft)
  • Cài extension: .NET Install Tool

Visual Studio 2022 (Windows/macOS):

  • IDE đầy đủ tính năng, phiên bản Community miễn phí
  • Trải nghiệm debug và refactoring tốt nhất
  • Tải về: visualstudio.microsoft.com

JetBrains Rider (đa nền tảng):

  • Refactoring và phân tích code tốt nhất
  • Trả phí (dùng thử 30 ngày miễn phí)

3. Tạo Dự Án Đầu Tiên

# Tạo ứng dụng console mới
dotnet new console -n MyFirstApp
cd MyFirstApp
 
# Chạy
dotnet run

File Program.cs được tạo ra sử dụng top-level statements (C# 9+):

// Program.cs — không cần class hay method Main!
Console.WriteLine("Hello, C#!");

Đây là cải tiến chất lượng lớn so với C# cũ, khi bạn phải viết:

// Phong cách cũ (vẫn hợp lệ, nhưng verbose)
namespace MyFirstApp;
 
class Program
{
    static void Main(string[] args)
    {
        Console.WriteLine("Hello, C#!");
    }
}

Cả hai đều hợp lệ. Series này sử dụng phong cách hiện đại.

Hệ Thống Kiểu .NET

C# là ngôn ngữ kiểu tĩnh và kiểu mạnh. Mỗi biến có một kiểu, được kiểm tra tại thời điểm biên dịch.

Value Types vs Reference Types

Đây là khái niệm cơ bản nhất trong C#. Không giống Python hay JavaScript nơi mọi thứ đều là object, C# phân biệt giữa hai loại:

Value types lưu trữ dữ liệu trực tiếp trên stack. Sao chép value type sẽ sao chép dữ liệu:

int a = 10;
int b = a;   // b nhận một bản sao của giá trị
b = 20;
Console.WriteLine(a); // 10 — không thay đổi

Reference types lưu trữ tham chiếu (con trỏ) trên stack; dữ liệu thực sự nằm trên heap. Sao chép reference type sẽ sao chép tham chiếu, không phải dữ liệu:

var list1 = new List<int> { 1, 2, 3 };
var list2 = list1;   // list2 trỏ đến cùng list
list2.Add(4);
Console.WriteLine(list1.Count); // 4 — cả hai biến đều thấy sự thay đổi

Các Value Types Tích Hợp Sẵn

// Kiểu số nguyên
byte   b = 255;          // 8-bit không dấu: 0 đến 255
short  s = 32_000;       // 16-bit có dấu
int    i = 2_000_000;    // 32-bit có dấu (phổ biến nhất)
long   l = 10_000_000_000L; // 64-bit có dấu
uint   u = 4_000_000_000u;  // 32-bit không dấu
 
// Kiểu số thực
float  f = 3.14f;        // 32-bit (dùng hậu tố 'f')
double d = 3.14159265;   // 64-bit (mặc định cho số thực)
decimal m = 19.99m;      // 128-bit, chính xác — dùng cho tiền!
 
// Các kiểu value khác
bool   flag = true;
char   c = 'A';          // Ký tự Unicode

Mẹo cho dev Python/JS: Dùng int cho số nguyên, double cho số thực thông thường, và decimal cho tính toán tài chính (tránh vấn đề độ chính xác floating-point).

Suy Luận Kiểu với var

C# hỗ trợ suy luận kiểu cục bộ:

var name = "Alice";         // string
var count = 42;             // int
var price = 9.99m;          // decimal
var items = new List<string>(); // List<string>

var là suy luận tại thời điểm biên dịch — kiểu được cố định tại thời điểm biên dịch. Dùng khi kiểu rõ ràng từ vế phải. Tránh var khi kiểu không rõ:

var result = GetData(); // Kiểu gì? Tránh điều này

Nullable Reference Types

Một trong những tính năng hiện đại mạnh mẽ nhất của C#. Bật nó trong file .csproj:

<PropertyGroup>
  <Nullable>enable</Nullable>
</PropertyGroup>

Bây giờ compiler theo dõi khả năng null:

string name = "Alice";      // Không thể là null
string? nickname = null;    // Có thể là null (chú ý dấu '?')
 
// Compiler cảnh báo trước khi dereferencing null
Console.WriteLine(name.Length);      // OK
Console.WriteLine(nickname.Length);  // Cảnh báo: có thể là null reference
 
// Các pattern an toàn
Console.WriteLine(nickname?.Length ?? 0); // Null-conditional + null-coalescing

Điều này phát hiện null reference exceptions tại thời điểm biên dịch thay vì runtime — cải tiến lớn so với Java hay Python.

Biến và Hằng Số

// Khai báo và khởi tạo
int count = 0;
string message = "Hello";
 
// Được suy luận
var user = "Alice";
 
// Hằng số (tại thời điểm biên dịch, phải là literal)
const int MaxRetries = 3;
const string AppName = "MyApp";
 
// Readonly (tại runtime, có thể được tính toán)
readonly DateTime startTime = DateTime.Now;

Quy ước đặt tên trong C#:

Thành phầnQuy ướcVí dụ
BiếncamelCaseuserName, totalCount
Hằng sốPascalCaseMaxRetries, DefaultTimeout
MethodsPascalCaseGetUser(), CalculateTotal()
ClassesPascalCaseUserService, OrderItem
InterfacesIPascalCaseIRepository, ILogger
Private fields_camelCase_name, _count

Điểm khác biệt quan trọng với Java: C# dùng PascalCase cho hằng số và methods công khai, không phải UPPER_SNAKE_CASE hay camelCase.

Control Flow

if / else

int score = 85;
 
if (score >= 90)
    Console.WriteLine("Điểm: A");
else if (score >= 80)
    Console.WriteLine("Điểm: B");
else if (score >= 70)
    Console.WriteLine("Điểm: C");
else
    Console.WriteLine("Điểm: F");

Switch Expressions (C# 8+)

C# hiện đại thay thế câu lệnh switch dài dòng bằng expression ngắn gọn:

// Câu lệnh switch cũ
string grade;
switch (score / 10)
{
    case 10:
    case 9: grade = "A"; break;
    case 8: grade = "B"; break;
    case 7: grade = "C"; break;
    default: grade = "F"; break;
}
 
// Switch expression hiện đại — gọn gàng hơn nhiều
string grade = (score / 10) switch
{
    >= 9 => "A",
    8    => "B",
    7    => "C",
    _    => "F"   // _ là pattern discard/default
};

Pattern Matching

Pattern matching của C# biểu cảm hơn instanceof của Java:

object obj = "Hello, World!";
 
// Type pattern
if (obj is string text)
    Console.WriteLine($"Chuỗi có độ dài {text.Length}");
 
// Property pattern
if (obj is string { Length: > 5 } longText)
    Console.WriteLine($"Chuỗi dài: {longText}");
 
// Switch với patterns
string description = obj switch
{
    int n when n > 0 => "số nguyên dương",
    int n when n < 0 => "số nguyên âm",
    string s         => $"chuỗi: {s}",
    null             => "null",
    _                => "thứ gì đó khác"
};

Vòng Lặp

// Vòng lặp for
for (int i = 0; i < 5; i++)
    Console.WriteLine(i);
 
// foreach (phổ biến nhất cho collections)
string[] fruits = ["Apple", "Banana", "Orange"]; // Collection expression C# 12
foreach (var fruit in fruits)
    Console.WriteLine(fruit);
 
// while
int count = 0;
while (count < 5)
{
    Console.WriteLine(count);
    count++;
}
 
// do-while
do
{
    Console.WriteLine("Chạy ít nhất một lần");
    count++;
} while (count < 5);

Methods

Methods trong C# luôn là thành viên của một kiểu (class, struct, hoặc record).

Cú Pháp Method Cơ Bản

// File-scoped namespace (C# 10+) — ít indent hơn
namespace LearningCSharp;
 
public class Calculator
{
    // Method có giá trị trả về
    public int Add(int a, int b) => a + b;  // Expression body
 
    // Void method
    public void PrintSum(int a, int b)
    {
        Console.WriteLine($"Tổng: {a + b}");
    }
 
    // Method với nhiều tham số
    public double Average(int[] numbers)
    {
        if (numbers.Length == 0) return 0;
        return (double)numbers.Sum() / numbers.Length;
    }
}

Các Modifier Tham Số

C# có các modifier tham số mạnh mẽ mà Java và Python không có:

public class ParameterExamples
{
    // ref — truyền theo tham chiếu (phải được khởi tạo trước)
    public void DoubleIt(ref int value)
    {
        value *= 2;
    }
 
    // out — trả về giá trị qua tham số (không cần khởi tạo trước)
    public bool TryDivide(int a, int b, out double result)
    {
        if (b == 0) { result = 0; return false; }
        result = (double)a / b;
        return true;
    }
 
    // in — tham chiếu chỉ đọc (cho structs lớn, tránh copy)
    public double GetLength(in Vector3 v) => Math.Sqrt(v.X * v.X + v.Y * v.Y + v.Z * v.Z);
 
    // params — tham số có độ dài thay đổi
    public int Sum(params int[] numbers) => numbers.Sum();
}
 
// Cách dùng
var calc = new ParameterExamples();
 
int x = 5;
calc.DoubleIt(ref x);
Console.WriteLine(x); // 10
 
if (calc.TryDivide(10, 3, out double quotient))
    Console.WriteLine(quotient); // 3.333...
 
int total = calc.Sum(1, 2, 3, 4, 5); // 15

Pattern TryDivide (trả về bool + tham số out) là C# idiomatico và được dùng trong toàn bộ thư viện chuẩn .NET (ví dụ: int.TryParse()).

Tham Số Tùy Chọn và Named Arguments

public void Greet(string name, string greeting = "Xin chào", bool uppercase = false)
{
    var message = $"{greeting}, {name}!";
    Console.WriteLine(uppercase ? message.ToUpper() : message);
}
 
// Cách dùng
Greet("Alice");                              // "Xin chào, Alice!"
Greet("Bob", "Chào");                        // "Chào, Bob!"
Greet("Carol", uppercase: true);             // "XIN CHÀO, CAROL!"
Greet("Dave", greeting: "Hey", uppercase: true); // "HEY, DAVE!"

Method Overloading

public class Printer
{
    public void Print(int value)    => Console.WriteLine($"int: {value}");
    public void Print(double value) => Console.WriteLine($"double: {value}");
    public void Print(string value) => Console.WriteLine($"string: {value}");
}

Strings

Strings trong C# là reference types bất biến — chúng hoạt động như value types trong thực tế.

String Interpolation

string name = "Alice";
int age = 30;
 
// String interpolation (ưu tiên dùng)
string message = $"Tên: {name}, Tuổi: {age}";
 
// Định dạng bên trong interpolation
double price = 9.99;
string formatted = $"Giá: {price:C}";        // "Giá: $9.99"
string padded   = $"{name,10}";               // "     Alice" (căn phải, rộng 10)
string dateStr  = $"{DateTime.Now:yyyy-MM-dd}"; // "2026-02-25"

Raw String Literals (C# 11+)

Cho chuỗi nhiều dòng không cần escape:

// Raw string literal — không cần escape dấu gạch chéo hay nháy
string json = """
    {
        "name": "Alice",
        "path": "C:\\Users\\Alice"
    }
    """;
 
// Interpolated raw string
string sql = $"""
    SELECT *
    FROM users
    WHERE name = '{name}'
    AND age > {age}
    """;

Các String Methods Phổ Biến

string text = "  Xin chào, C#!  ";
 
text.ToUpper()                // "  XIN CHÀO, C#!  "
text.ToLower()                // "  xin chào, c#!  "
text.Trim()                   // "Xin chào, C#!"
text.TrimStart()              // "Xin chào, C#!  "
text.Contains("C#")           // true
text.StartsWith("  Xin")      // true
text.Replace("C#", ".NET")    // "  Xin chào, .NET!  "
text.Split(',')               // ["  Xin chào", " C#!  "]
text.Substring(2, 8)          // "Xin chào"
 
// So sánh chuỗi (ordinal nhanh; dùng cho hầu hết trường hợp)
string.Equals("xin chào", "XIN CHÀO", StringComparison.OrdinalIgnoreCase) // true
 
// Kiểm tra null hoặc rỗng
string.IsNullOrEmpty(text)       // false
string.IsNullOrWhiteSpace("  ")  // true

StringBuilder cho Nối Chuỗi

// Không hiệu quả: tạo nhiều string object trung gian
string result = "";
for (int i = 0; i < 1000; i++)
    result += i + ",";
 
// Hiệu quả: bộ đệm mutable
var sb = new StringBuilder();
for (int i = 0; i < 1000; i++)
    sb.Append(i).Append(',');
string result = sb.ToString();

Records (C# 9+)

Records là một trong những tính năng hiện đại hữu ích nhất của C# — container dữ liệu bất biến với so sánh bằng giá trị được tích hợp sẵn:

// Positional record — cú pháp ngắn gọn
public record Person(string Name, int Age);
 
// Cách dùng
var alice = new Person("Alice", 30);
var bob   = new Person("Bob", 25);
var alice2 = alice with { Age = 31 }; // Thay đổi không phá hủy
 
Console.WriteLine(alice);   // Person { Name = Alice, Age = 30 }
Console.WriteLine(alice == new Person("Alice", 30)); // true — so sánh bằng giá trị!
Console.WriteLine(alice2);  // Person { Name = Alice, Age = 31 }

Records hoàn hảo cho DTOs, API responses và domain value objects. Chúng cung cấp:

  • Bất biến theo mặc định
  • ToString(), Equals(), GetHashCode() và == được triển khai tự động
  • Hỗ trợ deconstruction
  • with expressions cho cập nhật không phá hủy

Classes Cơ Bản và Properties

Auto-Properties

Properties của C# gọn hơn getters/setters của Java:

public class BankAccount
{
    // Auto-property với private setter
    public string Owner { get; private set; }
 
    // Auto-property — có thể đọc và ghi
    public decimal Balance { get; set; }
 
    // Init-only property (C# 9+) — chỉ set trong quá trình khởi tạo
    public string AccountNumber { get; init; }
 
    public BankAccount(string owner, string accountNumber)
    {
        Owner = owner;
        AccountNumber = accountNumber;
        Balance = 0m;
    }
 
    public void Deposit(decimal amount)
    {
        if (amount <= 0) throw new ArgumentException("Số tiền phải dương.");
        Balance += amount;
    }
}
 
// Cách dùng
var account = new BankAccount("Alice", "ACC-001");
account.Deposit(100m);
Console.WriteLine(account.Balance); // 100
 
// Object initializer syntax
var account2 = new BankAccount("Bob", "ACC-002") { Balance = 500m };

Primary Constructors (C# 12+)

// Primary constructor — tham số có sẵn trong toàn bộ class
public class Point(double x, double y)
{
    public double X { get; } = x;
    public double Y { get; } = y;
 
    public double DistanceTo(Point other)
    {
        var dx = X - other.X;
        var dy = Y - other.Y;
        return Math.Sqrt(dx * dx + dy * dy);
    }
 
    public override string ToString() => $"({X}, {Y})";
}
 
var p1 = new Point(0, 0);
var p2 = new Point(3, 4);
Console.WriteLine(p1.DistanceTo(p2)); // 5

File-Scoped Namespaces và Global Usings

Hai tính năng C# hiện đại giúp giảm đáng kể boilerplate:

File-Scoped Namespaces (C# 10+)

// Phong cách cũ — mọi thứ đều indent trong namespace block
namespace MyApp.Services
{
    public class UserService
    {
        // ...
    }
}
 
// Phong cách mới — namespace áp dụng cho toàn bộ file, không cần dấu ngoặc
namespace MyApp.Services;
 
public class UserService
{
    // ...
}

Global Usings (C# 10+)

Thêm file GlobalUsings.cs vào dự án:

// GlobalUsings.cs
global using System;
global using System.Collections.Generic;
global using System.Linq;
global using System.Text;
global using System.Threading.Tasks;

Bây giờ tất cả các file trong dự án đều có các namespace này mà không cần khai báo using rõ ràng.

Lưu ý: Các dự án .NET 6+ đã có implicit global usings được bật mặc định. Bạn có thể xem những gì được bao gồm trong obj/Debug/net8.0/MyApp.GlobalUsings.g.cs.

Cách .NET Biên Dịch và Chạy Code

Pipeline Biên Dịch

  1. Trình biên dịch C# (Roslyn) biên dịch file .cs thành IL (Intermediate Language)
  2. CLR (Common Language Runtime) tải IL
  3. JIT Compiler chuyển đổi IL thành machine code gốc tại runtime
  4. Trên .NET hiện đại, ReadyToRun (R2R) pre-biên dịch IL để khởi động nhanh hơn

Điều này tương tự mô hình JVM của Java, nhưng AOT compilation của .NET qua dotnet publish -r <rid> --self-contained có thể tạo ra file thực thi gốc không cần runtime dependency.

File Dự Án (.csproj)

File .csproj là XML đơn giản:

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net8.0</TargetFramework>
    <Nullable>enable</Nullable>
    <ImplicitUsings>enable</ImplicitUsings>
  </PropertyGroup>
</Project>
  • <Nullable>enable</Nullable> — bật nullable reference types (luôn làm điều này)
  • <ImplicitUsings>enable</ImplicitUsings> — bật default global usings

Best Practices cho Giai Đoạn 1

1. Luôn Bật Nullable Reference Types

<!-- Trong .csproj -->
<Nullable>enable</Nullable>

Coi cảnh báo của compiler về nullability như lỗi. Xử lý chúng đúng cách — đừng bỏ qua.

2. Dùng Expression Bodies cho Methods Đơn Giản

// Dài dòng
public int Add(int a, int b)
{
    return a + b;
}
 
// Ngắn gọn — ưu tiên cho các one-liner đơn giản
public int Add(int a, int b) => a + b;

3. Dùng TryParse Thay Vì Parse

// Không tốt — ném exception với input không hợp lệ
int value = int.Parse(userInput);
 
// Tốt — trả về false thay vì ném exception
if (int.TryParse(userInput, out int value))
    Console.WriteLine($"Hợp lệ: {value}");
else
    Console.WriteLine("Input không hợp lệ");

4. Ưu Tiên string.IsNullOrWhiteSpace Hơn != null

// Dễ vỡ — bỏ sót chuỗi rỗng và chuỗi chỉ có khoảng trắng
if (name != null) { ... }
 
// Mạnh mẽ
if (!string.IsNullOrWhiteSpace(name)) { ... }

5. Dùng Records cho Data Containers

// Thay vì một class với boilerplate getters/setters/equals:
public record Product(string Name, decimal Price, int StockCount);
 
// Bất biến, có thể so sánh, có thể in — không cần boilerplate

Những Lỗi Phổ Biến Cần Tránh

❌ Dùng == để So Sánh Chuỗi Với Các Case Khác Nhau

string a = "xin chào";
string b = "XIN CHÀO";
 
a == b; // false — so sánh phân biệt hoa thường
 
// ✅ Dùng StringComparison
string.Equals(a, b, StringComparison.OrdinalIgnoreCase); // true

❌ Không Xử Lý Nulls Khi Nullable Reference Types Được Bật

string? name = GetName(); // có thể trả về null
 
Console.WriteLine(name.Length); // Cảnh báo: có thể null dereference
 
// ✅ Kiểm tra null trước
if (name is not null)
    Console.WriteLine(name.Length);
 
// ✅ Hoặc dùng toán tử null-conditional
Console.WriteLine(name?.Length ?? 0);

❌ Nhầm Lẫn Giữa Value Type Copy và Reference Type Reference

// Value type — ngữ nghĩa sao chép
int a = 10;
int b = a;
b = 20;
Console.WriteLine(a); // 10 — không thay đổi
 
// Reference type — tham chiếu chia sẻ
var list1 = new List<int> { 1, 2, 3 };
var list2 = list1;
list2.Add(4);
Console.WriteLine(list1.Count); // 4 — list1 cũng thay đổi!

❌ Dùng float cho Tính Toán Tài Chính

float price = 0.1f + 0.2f;
Console.WriteLine(price); // 0.3 — nhưng thực ra là 0.30000001192...
 
// ✅ Dùng decimal cho tiền
decimal price = 0.1m + 0.2m;
Console.WriteLine(price); // 0.3 — chính xác

Bài Tập Thực Hành

Củng cố học tập của bạn với các bài tập sau:

  1. Bộ Chuyển Đổi Nhiệt Độ: Chuyển đổi Celsius ↔ Fahrenheit sử dụng record Temperature(double Value, string Unit) và switch expression
  2. FizzBuzz với Pattern Matching: Dùng switch expression với tuple patterns để triển khai FizzBuzz
  3. Phân Tích Chuỗi: Đếm từ, câu và nguyên âm trong một chuỗi; dùng StringBuilder cho output
  4. Tài Khoản Ngân Hàng Đơn Giản: Triển khai class BankAccount với các methods Deposit, Withdraw và Transfer; dùng decimal cho tiền
  5. Thực Hành TryParse: Viết chương trình đọc số nguyên từ console trong vòng lặp, dùng int.TryParse, và in tổng khi người dùng nhập số không hợp lệ

Tóm Tắt

Bạn đã học được những kiến thức C# cơ bản thiết yếu:

✅ Thiết lập môi trường phát triển .NET với SDK và IDE
✅ Hiểu value types vs reference types và khi nào dùng mỗi loại
✅ Dùng nullable reference types để kiểm tra null an toàn tại thời điểm biên dịch
✅ Viết control flow với switch expressions và pattern matching hiện đại
✅ Định nghĩa methods với ref, out, params và tham số tùy chọn
✅ Làm việc với strings, interpolation, raw string literals và StringBuilder
✅ Tạo classes cơ bản với auto-properties và primary constructors
✅ Dùng records cho các data container bất biến
✅ Áp dụng file-scoped namespaces và global usings để giảm boilerplate

Các Bước Tiếp Theo

Bạn đã sẵn sàng chuyển sang Giai Đoạn 2: Lập Trình Hướng Đối Tượng, nơi bạn sẽ học:

  • Kế thừa, method overriding và các từ khóa virtual/override/sealed
  • Interfaces, abstract classes và polymorphism
  • Encapsulation với access modifiers
  • Records nâng cao và with expressions
  • Extension methods và pattern matching chuyên sâu

🚀 Tiếp tục Giai Đoạn 2: Lập Trình Hướng Đối Tượng →


Series: Lộ Trình Học C#
Trước: Lộ Trình Học C# ←
Tiếp theo: Giai Đoạn 2: Lập Trình Hướng Đối Tượng →

Chúc bạn code vui! 💜

📬 Đăng ký nhận bản tin

Nhận những bài viết mới nhất qua email mỗi tuần. Không spam, hủy đăng ký bất cứ lúc nào.

Chúng tôi tôn trọng quyền riêng tư của bạn. Hủy đăng ký bất cứ lúc nào.

💬 Comments

Đăng nhập để bình luận

Chúng tôi sẽ không đăng bất cứ điều gì mà không có sự cho phép của bạn.