Sau khi hoàn thành bài tập này, bạn sẽ:
✅ Xây dựng lớp
SanPhamvới các thuộc tính cơ bản✅ Sử dụng static để tự động sinh mã sản phẩm
✅ Áp dụng validation cho dữ liệu
✅ Xây dựng phương thức nhập kho, xuất kho
✅ Sử dụng kiểu
decimalcho tiền tệ✅ Tính toán giá trị tồn kho tự động
BƯỚC 1: TẠO PROJECT MỚI
1.1. Mở Visual Studio
Mở Visual Studio 2022
Hoặc nhấn: Ctrl + Shift + N
1.3. Chọn loại Project
Gõ “Console” vào ô tìm kiếm
Chọn Console App (.NET Core) hoặc Console App (.NET Framework)
Nhấn Next
1.4. Đặt tên Project
Location: D:\CSharp\LapTrinhHuongDoiTuong (hoặc thư mục của bạn) Solution: LapTrinhHuongDoiTuong (chọn Add to Solution)
Nhấn Next
1.5. Chọn Framework
Chọn .NET 6.0 hoặc .NET 8.0 (LTS)
Nhấn Create
BƯỚC 2: TẠO CẤU TRÚC THƯ MỤC
2.1. Tạo thư mục Models
Trong Solution Explorer, click chuột phải vào Project
Bai2_SanPhamChọn Add → New Folder
Đặt tên:
ModelsNhấn Enter
BƯỚC 3: TẠO FILE LỚP SANPHAM
3.1. Tạo file SanPham.cs
Click chuột phải vào thư mục Models
Chọn Add → Class
Đặt tên:
SanPham.csNhấn Add
BƯỚC 4: VIẾT CODE CHO LỚP SANPHAM
4.1. Khai báo Namespace và Class
Mở file SanPham.cs và viết:
namespace Bai2_SanPham.Models { public class SanPham { // Code sẽ viết ở đây } }
4.2. Khai báo Fields (Trường dữ liệu)
{ // === FIELDS (Trường dữ liệu) === private string _maSP; // Mã sản phẩm (tự sinh) private string _tenSP; // Tên sản phẩm private decimal _donGia; // Đơn giá (dùng decimal cho tiền tệ) private int _soLuongTon; // Số lượng tồn kho private static int _soLuongSP = 0; // Đếm số SP đã tạo (static) }
Giải thích Fields:
| Field | Kiểu | Mục đích | Lưu ý |
|---|---|---|---|
_maSP | string | Lưu mã sản phẩm | Sẽ tự động sinh |
_tenSP | string | Lưu tên sản phẩm | Kiểm tra không rỗng |
_donGia | decimal | Lưu đơn giá | Dùng decimal cho tiền tệ |
_soLuongTon | int | Lưu số lượng tồn | Không được âm |
_soLuongSP | static int | Đếm số SP đã tạo | Dùng chung cho tất cả SP |
4.3. Khai báo Properties (Thuộc tính)
a. Property MaSP (Read-only – chỉ đọc)
public class SanPham { // ... Fields ở trên ... // === PROPERTIES === // 1. Mã sản phẩm - Chỉ đọc, tự sinh public string MaSP { get { return _maSP; } // Không có set → Không thể thay đổi từ bên ngoài } }
b. Property TenSP (Có validation)
// 2. Tên sản phẩm - Có kiểm tra không rỗng public string TenSP { get { return _tenSP; } set { // Kiểm tra tên không được để trống if (string.IsNullOrWhiteSpace(value)) throw new ArgumentException("Tên sản phẩm không được để trống!"); _tenSP = value.Trim(); } }
c. Property DonGia (Có validation)
// 3. Đơn giá - Không được âm public decimal DonGia { get { return _donGia; } set { if (value < 0) throw new ArgumentException("Đơn giá không được âm!"); _donGia = value; } }
d. Property SoLuongTon (Có validation)
// 4. Số lượng tồn - Không được âm public int SoLuongTon { get { return _soLuongTon; } set { if (value < 0) throw new ArgumentException("Số lượng tồn không được âm!"); _soLuongTon = value; } }
e. Property GiaTriTon (Computed – tự tính)
// 5. Giá trị tồn kho - Tự động tính (Read-only) public decimal GiaTriTon { get { return _soLuongTon * _donGia; } }
4.4. Khai báo Constructors (Phương thức khởi tạo)
a. Constructor mặc định (Tự sinh mã SP)
public class SanPham { // ... Fields và Properties ở trên ... // === CONSTRUCTORS === // Constructor 1: Không tham số - Tự sinh mã SP public SanPham() { // Tăng số lượng SP lên 1 trước _soLuongSP++; // Tự sinh mã SP: SP001, SP002, SP003, ... _maSP = "SP" + _soLuongSP.ToString("D3"); // Gán giá trị mặc định _tenSP = "Chưa xác định"; _donGia = 0; _soLuongTon = 0; } }
Giải thích:
_soLuongSP++– Tăng biến đếm lên 1ToString("D3")– Định dạng số thành 3 chữ số: 001, 002, 003, …_maSP = "SP" + "001"→ “SP001”
b. Constructor có tham số
// Constructor 2: Có tham số đầy đủ public SanPham(string tenSP, decimal donGia, int soLuongTon) : this() { // this() gọi constructor mặc định để tự sinh mã SP // Gán giá trị (có validation) TenSP = tenSP; DonGia = donGia; SoLuongTon = soLuongTon; }
Giải thích:
: this()– Gọi constructor mặc định trước (để tự sinh mã SP)Sau đó gán các giá trị khác
4.5. Khai báo Methods (Phương thức)
a. Phương thức HienThi()
public class SanPham { // ... Fields, Properties, Constructors ở trên ... // === METHODS === // 1. Hiển thị thông tin sản phẩm public void HienThi() { Console.WriteLine("═══════════════════════════════════════"); Console.WriteLine($" Mã SP : {_maSP}"); Console.WriteLine($" Tên SP : {_tenSP}"); Console.WriteLine($" Đơn giá : {_donGia:N0} VND"); Console.WriteLine($" SL Tồn : {_soLuongTon}"); Console.WriteLine($" Giá trị tồn : {GiaTriTon:N0} VND"); Console.WriteLine("═══════════════════════════════════════"); } }
b. Phương thức NhapKho()
// 2. Nhập kho (tăng số lượng tồn) public void NhapKho(int soLuong) { // Kiểm tra số lượng nhập phải > 0 if (soLuong <= 0) { Console.WriteLine("❌ Số lượng nhập phải lớn hơn 0!"); return; } // Tăng số lượng tồn _soLuongTon += soLuong; Console.WriteLine($"✓ Đã nhập kho {soLuong} sản phẩm. SL tồn: {_soLuongTon}"); }
c. Phương thức XuatKho()
// 3. Xuất kho (giảm số lượng tồn) public void XuatKho(int soLuong) { // Kiểm tra số lượng xuất phải > 0 if (soLuong <= 0) { Console.WriteLine("❌ Số lượng xuất phải lớn hơn 0!"); return; } // Kiểm tra số lượng tồn có đủ không if (soLuong > _soLuongTon) { Console.WriteLine($"❌ Không đủ hàng! Tồn: {_soLuongTon}, Yêu cầu: {soLuong}"); return; } // Giảm số lượng tồn _soLuongTon -= soLuong; Console.WriteLine($"✓ Đã xuất kho {soLuong} sản phẩm. SL tồn: {_soLuongTon}"); }
4.6. Code hoàn chỉnh của SanPham.cs
using System; namespace Bai2_SanPham.Models { public class SanPham { // === FIELDS === private string _maSP; private string _tenSP; private decimal _donGia; private int _soLuongTon; private static int _soLuongSP = 0; // === PROPERTIES === // 1. Mã sản phẩm - Read-only public string MaSP => _maSP; // 2. Tên sản phẩm - Có validation public string TenSP { get => _tenSP; set { if (string.IsNullOrWhiteSpace(value)) throw new ArgumentException("Tên sản phẩm không được để trống!"); _tenSP = value.Trim(); } } // 3. Đơn giá - Không được âm public decimal DonGia { get => _donGia; set { if (value < 0) throw new ArgumentException("Đơn giá không được âm!"); _donGia = value; } } // 4. Số lượng tồn - Không được âm public int SoLuongTon { get => _soLuongTon; set { if (value < 0) throw new ArgumentException("Số lượng tồn không được âm!"); _soLuongTon = value; } } // 5. Giá trị tồn kho - Tự động tính public decimal GiaTriTon => _soLuongTon * _donGia; // === CONSTRUCTORS === // Constructor mặc định - Tự sinh mã SP public SanPham() { _soLuongSP++; _maSP = "SP" + _soLuongSP.ToString("D3"); _tenSP = "Chưa xác định"; _donGia = 0; _soLuongTon = 0; } // Constructor có tham số public SanPham(string tenSP, decimal donGia, int soLuongTon) : this() { TenSP = tenSP; DonGia = donGia; SoLuongTon = soLuongTon; } // === METHODS === // 1. Hiển thị thông tin public void HienThi() { Console.WriteLine("═══════════════════════════════════════"); Console.WriteLine($" Mã SP : {_maSP}"); Console.WriteLine($" Tên SP : {_tenSP}"); Console.WriteLine($" Đơn giá : {_donGia:N0} VND"); Console.WriteLine($" SL Tồn : {_soLuongTon}"); Console.WriteLine($" Giá trị tồn : {GiaTriTon:N0} VND"); Console.WriteLine("═══════════════════════════════════════"); } // 2. Nhập kho public void NhapKho(int soLuong) { if (soLuong <= 0) { Console.WriteLine("❌ Số lượng nhập phải lớn hơn 0!"); return; } _soLuongTon += soLuong; Console.WriteLine($"✓ Đã nhập kho {soLuong} sản phẩm. SL tồn: {_soLuongTon}"); } // 3. Xuất kho public void XuatKho(int soLuong) { if (soLuong <= 0) { Console.WriteLine("❌ Số lượng xuất phải lớn hơn 0!"); return; } if (soLuong > _soLuongTon) { Console.WriteLine($"❌ Không đủ hàng! Tồn: {_soLuongTon}, Yêu cầu: {soLuong}"); return; } _soLuongTon -= soLuong; Console.WriteLine($"✓ Đã xuất kho {soLuong} sản phẩm. SL tồn: {_soLuongTon}"); } } }
BƯỚC 5: VIẾT CHƯƠNG TRÌNH KIỂM TRA (TEST)
5.1. Mở file Program.cs
Trong Solution Explorer, mở file Program.cs của Project Bai2_SanPham.
5.2. Viết code test
using System; using Bai2_SanPham.Models; // Import namespace để dùng class SanPham namespace Bai2_SanPham { class Program { static void Main(string[] args) { Console.OutputEncoding = System.Text.Encoding.UTF8; Console.WriteLine("===== BÀI TẬP 2: LỚP SẢN PHẨM =====\n"); // ============================================ // TEST 1: Constructor mặc định // ============================================ Console.WriteLine("1. Constructor mặc định:"); SanPham sp1 = new SanPham(); // Tạo SP với giá trị mặc định sp1.HienThi(); // Hiển thị thông tin // ============================================ // TEST 2: Constructor có tham số // ============================================ Console.WriteLine("\n2. Constructor có tham số:"); SanPham sp2 = new SanPham("Laptop Dell", 15000000, 10); sp2.HienThi(); // ============================================ // TEST 3: Tạo thêm sản phẩm để xem tự sinh mã // ============================================ Console.WriteLine("\n3. Tạo thêm sản phẩm:"); SanPham sp3 = new SanPham("Điện thoại iPhone", 25000000, 5); SanPham sp4 = new SanPham("Máy tính bảng", 8000000, 8); Console.WriteLine($" Mã SP3: {sp3.MaSP}"); Console.WriteLine($" Mã SP4: {sp4.MaSP}"); // ============================================ // TEST 4: Nhập kho // ============================================ Console.WriteLine("\n4. Nhập kho:"); sp2.NhapKho(5); // Nhập thêm 5 sản phẩm sp2.HienThi(); // Xem lại thông tin // ============================================ // TEST 5: Xuất kho (đủ hàng) // ============================================ Console.WriteLine("\n5. Xuất kho (đủ hàng):"); sp2.XuatKho(3); // Xuất 3 sản phẩm sp2.HienThi(); // ============================================ // TEST 6: Xuất kho (không đủ hàng) // ============================================ Console.WriteLine("\n6. Xuất kho (không đủ hàng):"); sp2.XuatKho(20); // Yêu cầu 20 nhưng chỉ có 12 // ============================================ // TEST 7: Validation - Tên rỗng // ============================================ Console.WriteLine("\n7. Kiểm tra validation (Tên rỗng):"); try { SanPham sp5 = new SanPham("", 100000, 5); } catch (Exception ex) { Console.WriteLine($" ❌ Lỗi: {ex.Message}"); } // ============================================ // TEST 8: Validation - Đơn giá âm // ============================================ Console.WriteLine("\n8. Kiểm tra validation (Đơn giá âm):"); try { SanPham sp6 = new SanPham("Sản phẩm test", -50000, 5); } catch (Exception ex) { Console.WriteLine($" ❌ Lỗi: {ex.Message}"); } Console.WriteLine("\nNhấn phím bất kỳ để thoát..."); Console.ReadKey(); } } }
BƯỚC 6: CHẠY CHƯƠNG TRÌNH
6.1. Build Project
Nhấn
Ctrl + Shift + Bđể biên dịchHoặc menu Build → Build Solution
6.2. Chạy chương trình
Nhấn
F5để chạy (Debug mode)Hoặc
Ctrl + F5để chạy không debug
KẾT QUẢ DỰ KIẾN
===== BÀI TẬP 2: LỚP SẢN PHẨM ===== 1. Constructor mặc định: ═══════════════════════════════════════ Mã SP : SP001 Tên SP : Chưa xác định Đơn giá : 0 VND SL Tồn : 0 Giá trị tồn : 0 VND ═══════════════════════════════════════ 2. Constructor có tham số: ═══════════════════════════════════════ Mã SP : SP002 Tên SP : Laptop Dell Đơn giá : 15,000,000 VND SL Tồn : 10 Giá trị tồn : 150,000,000 VND ═══════════════════════════════════════ 3. Tạo thêm sản phẩm: Mã SP3: SP003 Mã SP4: SP004 4. Nhập kho: ✓ Đã nhập kho 5 sản phẩm. SL tồn: 15 ═══════════════════════════════════════ Mã SP : SP002 Tên SP : Laptop Dell Đơn giá : 15,000,000 VND SL Tồn : 15 Giá trị tồn : 225,000,000 VND ═══════════════════════════════════════ 5. Xuất kho (đủ hàng): ✓ Đã xuất kho 3 sản phẩm. SL tồn: 12 ═══════════════════════════════════════ Mã SP : SP002 Tên SP : Laptop Dell Đơn giá : 15,000,000 VND SL Tồn : 12 Giá trị tồn : 180,000,000 VND ═══════════════════════════════════════ 6. Xuất kho (không đủ hàng): ❌ Không đủ hàng! Tồn: 12, Yêu cầu: 20 7. Kiểm tra validation (Tên rỗng): ❌ Lỗi: Tên sản phẩm không được để trống! 8. Kiểm tra validation (Đơn giá âm): ❌ Lỗi: Đơn giá không được âm! Nhấn phím bất kỳ để thoát...
BÀI TẬP VỀ NHÀ MỞ RỘNG
Thêm thuộc tính
NhaSanXuat(Nhà sản xuất)Thêm phương thức
CapNhatGia(decimal giaMoi)Thêm phương thức
KiemTraTonKho(int soLuongYeuCau)trả về true/falseTạo danh sách 5 sản phẩm và hiển thị báo cáo tổng giá trị tồn kho
Thêm validation cho tên sản phẩm (tối thiểu 2 ký tự)