Model: class, variable, property, comment, namespace, using

    15

    Bài học này sẽ hướng dẫn bạn thực hiện các bước để xây dựng class đầu tiên của dự án: lớp model. Class sẽ xây dựng trong bài đóng vai trò quan trọng và sẽ được sử dụng xuyên suốt các bài thực hành tiếp theo.

    Bài học này sẽ dẫn dắt từng bước thực hành để vận dụng các nội dung đã học trong phần lý thuyết. Nội dung chủ yếu của nhóm bài này là vận dụng các kỹ thuật xây dựng class sử dụng biến thành viênproperty trong class C#.

    Phân tích các thành phần của class sẽ xây dựng

    Như đã phân tích, một cuốn sách điện tử chứa những thông tin sau:

    1. tác giả (hoặc nhóm tác giả),
    2. tựa đề,
    3. nhà xuất bản,
    4. năm xuất bản,
    5. lần tái bản,
    6. mã ISBN (mã số tiêu chuẩn quốc tế cho sách),
    7. mô tả tóm tắt nội dung (dùng cho việc tìm kiếm),
    8. từ khóa mô tả nội dung/thể loại,
    9. đánh giá của cá nhân (rating, sau này có thể dùng trong sắp xếp),
    10. đánh dấu cuốn sách nào hiện đang đọc (để sau dễ dàng tìm đến những cuốn được đánh dấu),
    11. đường dẫn đầy đủ tới file sách.

    Đây là kết quả của quá trình trừu tượng hóa (phân tích và tách ra các thông tin đặc trưng mà chúng ta quan tâm) từ các cuốn sách về mặt thông tin.

    Từ sự trừu tượng hóa đó chúng ta xác định các nội dung cơ bản của class sẽ được xây dựng như bảng dưới đây:

    STTTênMô tảKiểuGhi chú
    1IdSố định danh duy nhấtSố nguyênBắt buộc
    2Nhóm tác giả (authors)Danh sách tên tác giả, phân tách bởi dấu phẩyVăn bảnBắt buộc
    3Tiêu đề (title)Tiêu đề sáchVăn bảnBắt buộc
    4Nhà xuất bản (publisher)Tên nhà xuất bảnVăn bảnBắt buộc
    5Năm xuất bản (year)Năm xuất bản sáchSố nguyênBắt buộc, phải lớn hơn 1950, nhỏ hơn năm hiện tại
    6Lần tái bản (edition)Lần tái bản của sáchSố nguyênBắt buộc, phải lớn hơn hoặc bằng 1, mặc định là 1
    7Mã xuất bản (Isbn)Mã số tiêu chuẩn quốc tếVăn bảnKhông bắt buộc
    8Từ khóa (tags)Danh sách các từ khóa mô tả nội dung, thể loạiVăn bảnKhông bắt buộc
    9Mô tả (description)Mô tả tóm tắt nội dungVăn bảnKhông bắt buộc
    10Đường dẫn (file)Đường dẫn (đầy đủ) tới file pdfVăn bảnBắt buộc, phải là một đường dẫn đúng
    11Đánh dấu đọc (reading)Dùng để đánh dấu một cuốn sách đang đọcLogicKhông bắt buộc, mặc định là false
    12Đánh giá (rating)Đánh giá chất lượng cuốn sáchSố nguyênKhông bắt buộc, có giá trị từ 1 (dở nhất) đến 5 (tốt nhất), mặc định là 1

    Từ đây, chúng ta sẽ xây dựng class đầu tiên với C#. Loại class chỉ chứa thông tin của đối tượng bị quản lý cũng được gọi là class thực thể (entity class).

    Thực hành 1: xây dựng class Book với biến thành viên

    Bước 1. Tạo file mã nguồn cho class

    Click phải vào thư mục Models, chọn Add => New Item … hoặc bấm tổ hợp Ctrl + Shift + A.

    Thêm class mới cho project
    Thêm class mới cho project

    Trong hộp thoại “Add New Item” chọn “Class”; trong hộp văn bản “Name” nhập “Book”.

    Đặt tên file (và tên class)
    Đặt tên file (và tên class)

    Bấm nút “Add” hoặc phím “Enter”. Một file mã nguồn mới “Book.cs” đã được thêm vào thư mục Models với nội dung như sau:

    File mã nguồn của class mới tạo
    File mã nguồn của class mới tạo

    Bước 2. Viết code cho lớp Book

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    namespace BookMan.ConsoleApp.Models
    {
        class Book
        {
            int _id;
            string _authors;
            string _title;
            string _publisher;
            int _year;
            int _edition;
            string _isbn;
            string _tags;
            string _description;
            int _rating;
            bool _reading;
            string _file;
        }
    }

    Khi xây dựng class Book bạn đã vận dụng quy ước sau:

    • đặt tên class kiểu PascalCase;
    • đặt toàn bộ code của mỗi class trong một file code riêng cùng tên;
    • áp dụng quy ước đặt tên biến thành viên private theo camelCase với dấu _ ở đầu.

    Thực hành 2: sử dụng biến public

    Trong đoạn code trước, tất cả biến thành viên của “Book” đều được khai báo là “private” và cũng không được gán giá trị đầu. Chúng ta sẽ cải tiến để các trường dữ liệu của “Book” trở thành “public” và gán giá trị đầu phù hợp. Điều chỉnh code của “Book” như sau:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    namespace BookMan.ConsoleApp.Models
    {
        public class Book
        {
            public int Id = 1;
            public string Authors = "Unknown authors";
            public string Title = "A new book";
            public string Publisher = "Unknown publisher";
            public int Year = 2018;
            public int Edition = 1;
            public string Ibn;
            public string Tags;
            public string Description = "A new book";
            public int Rating = 1;
            public bool Reading = false;
            public string File;
        }
    }

    Với cải tiến này, các object (biến) tạo ra từ kiểu Book cho phép truy xuất các trường dữ liệu chứa trong nó và có thể được sử dụng để lưu trữ dữ liệu cho các cuốn sách điện tử đang cần quản lý.

    Cũng lưu ý cách đặt tên biến public theo quy ước PascalCase.

    Tuy nhiên, cải tiến này có một nhược điểm: các biến thành viên của class này có thể bị truy xuất trực tiếp và chúng ta không kiểm soát được giá trị gán cho chúng.

    Ví dụ về yêu cầu giá trị của các trường:

    • Id: không nhận giá trị nhỏ hơn 1;
    • Authors, Title, Publisher: không được nhận xâu rỗng;
    • Edition: không được nhận các giá trị nhỏ hơn 1;
    • Rating: chỉ nhận các giá trị từ 1 đến 5, tương đương với các mức đánh giá từ xấu đến tốt;
    • File: chỉ chấp nhận đường dẫn chính xác tới file sách pdf.

    Thực hành 3: sử dụng auto property

    Thay đổi code của class Book như sau:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    namespace BookMan.ConsoleApp.Models
    {
        public class Book
        {
            public int Id { get; set; } = 1;
            public string Authors { get; set; } = "Unknown author";
            public string Title { get; set; } = "A new book";
            public string Publisher { get; set; } = "Unknown publisher";
            public int Year { get; set; } = 2018;
            public int Edition { get; set; } = 1;
            public string Isbn { get; set; }
            public string Tags { get; set; }
            public string Description { get; set; } = "A new book";
            public int Rating { get; set; } = 1;
            public bool Reading { get; set; }
            public string File { get; set; }
        }
    }

    Lưu ý cách đặt tên property theo quy ước PascalCase.

    Bạn có thể sử dụng Code snippet để nhanh chóng tạo ra property theo cách sau:

    1. Nhập cụm “prop” => trong danh sách lựa chọn của Visual Studio IntelliSense xuất hiện mục “prop” => chọn mục này và bấm phím Tab hai lần.
    2. Trong snippet vừa tạo chỉnh sửa các thông tin cần thiết (phần code được bôi vàng). Di chuyển giữa các vùng bôi vàng bằng phím Tab. Kết thúc chỉnh sửa snippet bằng phím Enter.
    Sử dụng snippet "prop" để tạo property

    So sánh với code cũ bạn có thể thấy sau tên của mỗi trường dữ liệu xuất hiện một khối code { get; set; }. Phần thực hành này hoàn toàn sử dụng auto property.

    Thực hành 4: sử dụng full property

    Như đã phân tích, trong class “Book” có một số giới hạn cần đặt ra với dữ liệu:

    • Id không nhận giá trị nhỏ hơn 1;
    • Authors, Title, Publisher không được nhận xâu rỗng;
    • Year không nhận các giá trị nhỏ hơn 1950 (sách cũ quá!);
    • Edition không nhận giá trị nhỏ hơn 1;
    • Rating chỉ nhận giá trị trong khoảng [1, 5];
    • File chỉ được nhận giá trị là đường dẫn chính xác tới file.

    Ngoài ra, chúng ta cũng muốn tạo ra một trường trong đó chứa tên ngắn gọn của File sách (để tiện sử dụng trong một số trường hợp).

    Chúng ta thay đổi code của class “Book” như sau:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    namespace BookMan.ConsoleApp.Models
    {
        public class Book
        {
            private int _id = 1;
            public int Id
            {
                get { return _id; }
                set { if (value >= 1) _id = value; }
            }
            private string _authors = "Unknown author";
            public string Authors
            {
                get { return _authors; }
                set { if (!string.IsNullOrEmpty(value)) _authors = value; }
            }
            private string _title = "A new book";
            public string Title
            {
                get { return _title; }
                set { if (!string.IsNullOrEmpty(value)) _title = value; }
            }
            private string _publisher = "Unknown publisher";
            public string Publisher
            {
                get { return _publisher; }
                set { if (!string.IsNullOrEmpty(value)) _publisher = value; }
            }
            private int _year = 2018;
            public int Year
            {
                get { return _year; }
                set { if (value >= 1950) _year = value; }
            }
            private int _edition = 1;
            public int Edition
            {
                get { return _edition; }
                set { if (value >= 1) _edition = value; }
            }
            public string Isbn { get; set; } = "";
            public string Tags { get; set; } = "";
            public string Description { get; set; } = "A new book";
            private int _rating = 1;
            public int Rating
            {
                get { return _rating; }
                set { if (value >= 1 && value <= 5) _rating = value; }
            }
            public bool Reading { get; set; }
            private string _file;
            public string File
            {
                get { return _file; }
                set { if (System.IO.File.Exists(value)) _file = value; }
            }
            public string FileName
            {
                get { return System.IO.Path.GetFileName(_file); }
            }
        }
    }

    Như vậy, phần thực hành này đã vận dụng full property để kiểm soát dữ liệu nhập vào cho các trường backed field.

    Thực hành 5: sử dụng documentation comment

    Các bạn đã biết, C# sử dụng một loại chú thích đặc biệt gọi là chú thích tài liệu (documentation comment). Loại chú thích này rất có ích cho người lập trình vì nó giúp mô tả các đơn vị code như class, method, interface, v.v. xuyên suốt trong project.

    Phần thực hành này sẽ bổ sung các chú thích cần thiết cho lớp Book.

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    namespace BookMan.ConsoleApp.Models
    {
        /// <summary>
        /// Lớp mô tả sách điện tử
        /// </summary>
        public class Book
        {
            private int _id = 1;
            /// <summary>
            /// số định danh duy nhất cho mỗi object
            /// </summary>
            public int Id
            {
                get { return _id; }
                set { if (value >= 1) _id = value; } // id chỉ nhận giá trị >= 1
            }
            private string _authors = "Unknown author";
            /// <summary>
            /// tên tác giả hoặc nhóm tác giả, không nhận xâu rỗng
            /// </summary>
            public string Authors
            {
                get { return _authors; }
                set { if (!string.IsNullOrEmpty(value)) _authors = value; } // không nhận xâu rỗng
            }
            private string _title = "A new book";
            /// <summary>
            /// tiêu đề sách, không nhận xâu rỗng
            /// </summary>
            public string Title
            {
                get { return _title; }
                set { if (!string.IsNullOrEmpty(value)) _title = value; } // không nhận xâu rỗng
            }
            private string _publisher = "Unknown publisher";
            /// <summary>
            /// nhà xuất bản, không nhận xâu rỗng
            /// </summary>
            public string Publisher
            {
                get { return _publisher; }
                set { if (!string.IsNullOrEmpty(value)) _publisher = value; } // không nhận xâu rỗng
            }
            private int _year = 2018;
            /// <summary>
            /// năm xuất bản, không nhỏ hơn 1950
            /// </summary>
            public int Year
            {
                get { return _year; }
                set { if (value >= 1950) _year = value; } // năm không nhỏ hơn 1950
            }
            private int _edition = 1;
            /// <summary>
            /// lần tái bản, không nhỏ hơn 1
            /// </summary>
            public int Edition
            {
                get { return _edition; }
                set { if (value >= 1) _edition = value; } // không nhận giá trị < 1
            }
            /// <summary>
            /// mã số quốc tế
            /// </summary>
            public string Isbn { get; set; } = "";
            /// <summary>
            /// từ khóa mô tả nội dung / thể loại
            /// </summary>
            public string Tags { get; set; } = "";
            /// <summary>
            /// mô tả tóm tắt nội dung
            /// </summary>
            public string Description { get; set; } = "A new book";
            private int _rating = 1;
            /// <summary>
            /// đánh giá cá nhân, giá trị từ 1 đến 5
            /// </summary>
            public int Rating
            {
                get { return _rating; }
                set { if (value >= 1 && value <= 5) _rating = value; } // giá trị từ 1 đến 5
            }
            /// <summary>
            /// đánh dấu là đang đọc
            /// </summary>
            public bool Reading { get; set; }
            private string _file;
            /// <summary>
            /// file sách (gồm dường dẫn)
            /// </summary>
            public string File
            {
                get { return _file; }
                set { if (System.IO.File.Exists(value)) _file = value; } // nhận đường dẫn đúng
            }
            /// <summary>
            /// file sách (không có đường dẫn)
            /// </summary>
            public string FileName
            {
                get { return System.IO.Path.GetFileName(_file); } // trả lại tên file ngắn gọn
            }
        }
    }

    Khi class (và kiểu dữ liệu nói chung), property hoặc phương thức có chú thích tài liệu, nếu đặt con trỏ chuột lên trên sẽ xuất hiện thông tin này, giúp người lập trình (bản thân hoặc người khác) dễ dàng hiểu được tác dụng của các đơn vị code này.

    Mỗi loại đối tượng trong C# đều được Visual Studio hiển thị bằng một biểu tượng riêng. Như class, method, property, variable đều được biểu thị bằng một biểu tượng riêng, giúp người lập trình dễ dàng nhận biết đây là loại đối tượng nào.

    Biểu tượng kết hợp với chú thích tài liệu hỗ trợ rất tốt cho việc tự tìm hiểu code.

    Dưới đây là ví dụ đối với class “Book” và thuộc tính “Authors”. Trong hình là cách Visual Studio hiển thị ghi chú tài liệu khi đặt con trỏ chuột vào tên class Book và thuộc tính Authors. Cũng lưu ý biểu tượng của class và property.

    Biểu tượng class trong Visual Studio
    Biểu tượng class trong Visual Studio
    Biểu tượng property trong Visual Studio
    Biểu tượng property trong Visual Studio

    Nên tập thành thói quen ghi chú code. Đối với các khai báo kiểu, property, method thì nên dùng documentation comment. Trong thân phương thức thì dùng comment thông thường.

    Thực hành 6: thu gọn khối using, làm gọn code

    Sau khi hoàn thành một class có thể xóa bỏ những mục using không sử dụng tới để file code gọn gàng hơn. Visual Studio 2017 hỗ trợ tính năng thông báo này bằng cách hiện màu nhạt cho những mục using thừa (không sử dụng class nào trong namespace tương ứng). Xóa bỏ những mục này là an toàn và giúp code nhìn gọn gàng hơn.

    Visual Studio cung cấp một Quick Action để “thu dọn” khối using: đặt con trỏ vào vùng using (chỗ hiện màu nhạt); kích hoạt Quick Action (tổ hợp Ctrl + .); chọn Remove Unnecessary Usings.

    Sử dụng quick action để dọn dẹp khối using
    Sử dụng quick action để dọn dẹp khối using

    Để format lại toàn bộ code theo quy ước viết code chung của Visual Studio, bạn bấm tổ hợp Ctrl + K + D.

    Đến đây xin chức mừng bạn đã xây dựng được một class đầu tiên “theo kiểu C#”.

    Kết luận

    Bài học này giúp bạn tổng hợp và vận dụng các kiến thức đã học về cách xây dựng class cơ bản trong C#. Nội dung chủ yếu của nhóm bài này là kỹ thuật xây dựng class sử dụng biến thành viênproperty trong class C#.

    Khi vận dụng các kỹ thuật này một cách phù hợp, bạn đã tạo ra được một class thực thể Book một cách “chuyên nghiệp” “theo kiểu C#”.

    + Nếu bạn thấy site hữu ích, trước khi rời đi hãy giúp đỡ site bằng một hành động nhỏ để site có thể phát triển và phục vụ bạn tốt hơn.
    + Nếu bạn thấy bài viết hữu ích, hãy giúp chia sẻ tới mọi người.
    + Nếu có thắc mắc hoặc cần trao đổi thêm, mời bạn viết trong phần thảo luận cuối trang.
    Cảm ơn bạn!

    Theo dõi
    Thông báo của
    guest

    15 Thảo luận
    Cũ nhất
    Mới nhất
    Phản hồi nội tuyến
    Xem tất cả bình luận
    trinh ngoc

    nếu như theo các bài trước chúng ta sẽ viết 1 cái class book. trong đó có luôn 3 phần biến thành viên, hàm khởi tạo và các method print, render luôn trong cùng class đó.
    gía sách thì sẽ viết 1 cái List

    ở đây nếu muốn in ra 1 cuốn sách thì. chúng ta phải tạo 1 object từ class singleview mà dùng method của nó để in ra.

    tẩu hoả nhập ma. aaaaaa

    trinh ngoc

    mình chưa hiểu rõ về cái tư duy nên xây dựng những class nào. khi mới bắt tay vào học bài này mình tưởng tượng ở đây như 1 cái cửa hàng sách. bên trong cửa hàng kê các giá sách được phân loại theo các thể loại sách giáo khoa, truyện, sách chính trị … vậy mình có thể viết 1 class bookshelf (Giá sách) bên trong chứa các object sách không. nếu được thì nó gồm những biến, phương thức gì. Kể cả tư duy như vậy nhưng mình cũng không biết nên code thế nào cho đúng.… Đọc tiếp »

    trinh ngoc

    đúng là sẽ phải học rất nhiều skill để tự mình tạo ra 1 sơ đồ lớp hoàn chỉnh cho bài này. vấn đề lớn ở đây mình đã có ý tưởng (hơi thô thiển 🙂 nhưng lại ko viết cụ thể ra code được. bạn làm mẫu cho mình được không. mình đã có class Book như trên. Muốn viết class BookShelf. các giá sách này chỉ khác nhau về tên. (VD: sách chính trị, văn học, …) trên đó đặt các loại sách theo phân loại. giá sách lưu trữ sách bằng LIST. mình cứ bị loạn phần… Đọc tiếp »

    trinh ngoc

    Đúng ý mình rồi. sở học của mình khá là hỗn tạp. đã học xong tin học cơ bản, cấu trúc dữ liệu và giải thuật, SQL, winform (VB), bash shell nhưng tất cả đều là những module nhỏ. Khi bắt tay vào làm những bài tập lớn theo hướng đối tượng như thế này thấy khiếm khuyết ngay từ bước thiết kế ban đầu cho ứng dụng. Mình đã học hỏi được rất nhiều qua seri này. qua các bài tập ví dụ thế này có lẽ mình sẽ học thêm được cách xâu chuỗi các phần kiến thức… Đọc tiếp »

    trinh ngoc

    à mở rộng hơn 1 chút nữa. vậy khi mình tổ chức theo mô hình MVC. hàm khởi tạo của các class này đặt ở luôn ở class trong Model? còn các method như Add() Remove() book của bookshelf thì nên tách ra thành 2 class riêng trong thư mục View nhỉ? (vì bạn nói các thứ liên quan đến xuất nhập thì chuyển sang view mà) nhưng như vậy thì nó sẽ đâu còn là method của bookshelf nữa??? và như vậy sao không sử dụng partial class để chia class bookshelf thành 2 phần: phần biến và khởi… Đọc tiếp »

    dhhehhs

    sao cái phương thức List.Add() nó chỉ thực hiện được khi list != null nhỉ?
    trong trường hợp nó = null mình đã phải làm như sau.

    Bookshelf. Books = new List {book}
    else
    Books.Add(book)

    trinh ngoc

    wow. search những cái bộ nguyên lý SOLID này trên web đều có đủ cả. tài nguyên học thật là đồ sộ. mà toàn lên top1 google. SEO web tốt thật.

    huy

    Hơi muộn nhưng nếu bạn có học qua phân tích yêu cầu và đặc tả phần mềm thì nó sẽ là những cái class này đó :v

    Nam

    Bài viết hay ghê, không biết bên mình có dạy lập trình c# từ cơ bản tới nâng cao không nhỉ ?

    Ý mình là khóa học hoàn chỉnh có phí.

    Lần cuối chỉnh sửa 2 năm trước bởi Nam
    dhatuan

    rất chi tiết và dễ học. Cảm ơn tác giả

    Kim Sa

    Cách sử dụng full property này có thể so sánh với System.ComponentModel.DataAnnotations không ạ?
    Và có thể thay thế bằng System.ComponentModel.DataAnnotations không ạ?
    Em cám ơn chị!