5/10/16

Một số quy định viết code trong lập trình C#

Khi lập trình trong một nhóm nhất thiết phải có các quy chuẩn lập trình chung như cách đặt tên biến, hàm, thụt lề,... Việc viết code theo quy chuẩn sẽ giúp các thành viên trong nhóm dễ dàng đọc code của nhau cũng như dễ bảo trì và sửa lỗi hơn. Mỗi ngôn ngữ lập trình lại có một "trường phái code" khác nhau với những quy định khác nhau. Việc đặt ra quy định code cũng nên tuân theo trường phái của ngôn ngữ đó. Dưới đây là các quy định code trong ngôn ngữ C# và đã được áp dụng cho nhóm của mình. Các bạn có thể dựa theo các quy định bên dưới để đặt ra quy định riêng phù hợp với nhóm của các bạn.


1. Quy tắc đặt tên (Name convention)

1.1. Các phong cách đặt tên phổ biến

KiểuMô tảVí dụ
PascalViết hoa chữ cái đầu tiên của mỗi từ.PascalCase
CamelViết thường chữ cái đầu của từ đầu tiên. Các từ còn lại viết hoa chữ cái đầu.camelCase
UppercaseIn hoa toàn bộ tênUPPERCASE
Hungarian NotationGồm phần tiền tố chỉ kiểu dữ liệu hoặc đặc trưng của biến và phần tên với mỗi từ được bắt đầu bằng chữ in hoa.iTuSo, strName

1.2. Một số quy định đặt tên

Tên cần phải thể hiện được ý nghĩa một cách tường minh. Tránh những cách đặt tên mơ hồ, khó hiểu (chấp nhận đặt tên bằng 1 chữ cái cho những đối tượng hiển nhiên ai cũng hiểu).

Tránh thêm các tiền tố hoặc hậu tố dư thừa vô nghĩa.

NênKhông nên
enum Color { ... }
class DateTime { ... }
struct Fraction { ... }
enum ColorEnum { ... }
class CDateTime { ... }
struct FractionStruct { ... }

Không thêm tên lớp chứa vào tên thuộc tính.

NênKhông nên
HocSinh.TenHocSinh.TenHocSinh

Tên biến, phương thức bool phải thể hiện được ngay ý nghĩa nếu trả về true hoặc false. Để làm điều này, nên sử dụng tiền tố “Is” “Can” “Has” trước tên biến, phương thức.

NênKhông nên
bool IsPrime(int n) { }
bool IsValid() { }
bool isChecked = true;
        
bool CheckPrime(int n) { }
bool Valid() { }
bool checked = true;

Tên được đặt theo quy tắc sau:

LoạiKiểu đặt tênVí dụGhi chú
Tên biếnCamelbackColorDanh từ
Hằng sốUppercaseNUMBER_OF_STUDENTCó gạch chân giữa các từ
Tên class, enumPascalSmartSnakeDanh từ
Tham sốCameldisplayTimeDanh từ
Thuộc tínhPascalBackColorDanh từ
Phương thứcPascalGetPath()Động từ
Sự kiệnPascalTextChangedEventHandlerCó hậu tố EventHandler
Giao diện (interface)PascalIButtonControlCó tiền tố I


1.3. Tiền tố một số control

Bắt buộc đặt tên cho tất cả các control có tham gia xử lý dưới nền. Tên control được đặt theo kiểu Pascal với phần tiền tố như sau:

ControlTiền tốVí dụ
PanelpnlpnlGroup
Check boxchkchkReadOnly
Combo box, drop-down list boxcbocboEnglish
ButtonbtnbtnExit
DialogdlgdlgFileOpen
DataTabledtdtBiblio
Data-bound combo boxcbocboLanguage
Data-bound gridgridgridQueryResult
Data-bound list boxlstlstJobType
DateTimePickerdatedatePublished
FormfrmfrmEntry
DataGridViewgridgridPrices
Horizontal scroll barhbhbVolume
ImageimgimgIcon
ImageListimglsimglsAllIcons
HyperLinklnklnkHome
LabellbllblHelpMessage
List boxlslsPolicyCodes
ListViewlvwlvwHeadings
MenumnumnuFileOpen
Picture boxpicpicVGA
ProgressBarprgprgLoadFile
RichTextBoxrtfrtfReport
StatusBarsttsttDateTime
TextBoxtxttxtLastName
TimertmtmAlarm
ToolbartbtbActions
TreeViewtvtvOrganization
NumericUpDownnumnumMonth
Vertical scroll barvbvbRate
DataSourcedsdsSql


2. Phong cách lập trình

2.1. Quy định phân bố mã nguồn

Mỗi file mã nguồn chỉ chứa duy nhất một class. Tên class chính phải trùng với tên file mã nguồn. Ví dụ: Class SchoolWork sẽ được chứa trong file SchoolWork.cs.

Với các kiểu enum, struct độc lập đơn giản ngoài class có thể được khai báo trong một file mã nguồn riêng hoặc trong file mã nguồn của class khác.

Interface phải được khai báo trong một file mã nguồn riêng.

Thứ tự khai báo:
Chú thích tên chương trình, tác giả, v.v
/// IPv4 Calculator
/// A simple tool to subnetting IPv4 addresses
/// Copyright (c) 2015 Nguyễn Tuấn            
            
Khối khai báo thư viện
using System.Collections.Generic;
using System.Xml;               
            
Khai báo namespace
namespace IPv4Calculator
{
            
Khai báo các struct/enum độc lập (nếu có)
    public enum IPv4Class { A, B, C, D, E }

            
Khai báo lớp chính
    public class IPv4Address : NetworkAddress
    {
    
    }
}
            


2.2. Quy ước viết câu lệnh

Mỗi câu lệnh riêng rẽ trên một dòng.

NênKhông nên
private int x = 3;
private int y = 5;
if (a > b)
    a++;
else
    b++;
        
private int x = 3, y = 5;
if (a > b) a++;
else b++;


Đối với biến kiểu bool, tránh dùng phép so sánh với true hoặc false.

NênKhông nên
if (isValidFirst 
        && isValidSecond)
    DoSomeThing();

if (!item.IsValid())
    item.Remove();
        
if (isValidFirst == true 
    && isValidSecond == true)
    DoSomeThing();

if (item.IsValid() == false)
    item.Remove();


2.3. Khối mã nguồn

Sử dụng cặp dấu { } để đánh dấu một khối mã nguồn. Mỗi dấu ngoặc nằm trên một dòng (Ngoại lệ, kiểu enum, thuộc tính gọn hoặc khởi tạo giá trị cho mảng có thể không cần).

Trong các lệnh if, for, foreach, ... nếu chỉ có một lệnh thì có thể không cần đánh dấu khối mã nguồn.

Sau đây là các ví dụ:

NênKhông nên
if (isValid)
{
    Console.WriteLine("Hello!");
}

if (isValid)
    Console.WriteLine("Hello!");
        
if (isValid) {
    Console.WriteLine("Hello!");
}
void Swap(ref int a, ref int b)
{
    int c = a;
    a = b;
    b = c;
}
        
void Swap(ref int a, ref int b)
{   int c = a;
    a = b;
    b = c;
}

void Swap(ref int a, ref int b) {
    int c = a;
    a = b;
    b = c;
}


2.4. Thụt đầu hàng và cách khoảng

Viết cách vào một khoảng tab đối với các lệnh nằm trong khối lệnh { }.
Viết cách vào một khoảng tab đối với lệnh ngay sau if, else, while, for, foreach.
Viết cách một khoảng trắng xung quanh các toán tử 2 ngôi và 3 ngôi.
Viết cách một khoảng trắng sau dấu “,” và “;”

2.5. Chú thích

Khuyến khích comment trên những đoạn code khó hiểu hoặc chức năng đặc biệt. Ngôn ngữ sử dụng để chú thích phải đồng bộ xuyên suốt chương trình. Chọn một trong hai ngôn ngữ: tiếng Việt Unicode có dấu hoặc tiếng Anh.

Quy định chú thích:
  • Chỉ sử dụng // và /// để chú thích. Không dùng /* */.
  • Có chú thích trên đầu mỗi file source code mô tả chương trình, chức năng của chương trình, tác giả, v.v...
  • Khối xử lý dữ liệu: Có chú thích trên mỗi class, mỗi phương thức, mỗi thuộc tính của class mô tả chức năng, tham số, v.v...
  • Khối xử lý giao diện: Có chú thích mô tả chức năng trên mỗi phương thức không phải event, hàm Main.

Các kiểu chú thích:
Chú thích đơn giản dùng cho:
  • Đoạn code phức tạp
  • Mô tả trong thân hàm
  • Mô tả field
  • Đoạn code được người không phải tác giả sửa đổi

Ví dụ:
 
private void btnSubnetting_Click(object sender, EventArgs e)
{
    if (isSubnetting)
    {
        //Preparations for UI
        btnSubnetting.Text = "Cancel";
        isSubnetting = false;
        if (numNumberOfSubnets.Value > 2000)
            progressBar.Visible = true;
                
        //Start thread
        subnettingThread = new Thread(new ThreadStart(Subnetting));
        subnettingThread.SetApartmentState(ApartmentState.MTA);
        subnettingThread.IsBackground = true;
        subnettingThread.Start();
    }
    else
    {
        //Abort thread
        subnettingThread.Abort();

        //Update UI
        btnSubnetting.Text = "Subnetting";
        isSubnetting = true;
        lvwSubnetting.EndUpdate();
        progressBar.Visible = false;
        progressBar.Value = progressBar.Minimum;
    }          
}
Chú thích đầy đủ dùng cho:
  • Phương thức
  • Class
  • Các struct, enum độc lập
Mẹo: Trong Visual Studio hỗ trợ sẵn macro cho các chú thích phức tạp. Sử dụng như sau: Gõ /// lên đầu mỗi method, class, ...

Ví dụ:
/// <summary>
/// Represents octets in IPv4 address.
/// </summary>
public class Octet
{
    /// <summary>
    /// Gets binary value of octet.
    /// </summary>
    public string Binary { get; }

    /// <summary>
    /// Represent decimal value of octet.
    /// </summary>
    public int Decimal { get; set; }

    /// <summary>
    /// Convert an integer value to string of binary value.
    /// </summary>
    /// <param name="n">A positive integer value less than 256.</param>
    /// <returns></returns>
    private string ToBinary(int n)
    {
        string result = "";

        while (n > 0)
        {
            result = (n % 2).ToString() + result;
            n /= 2;
        }
        while (result.Length < 8)
            result = "0" + result;

        return result;
    }
}

2.6. Cách dòng, xuống dòng đối với code dài

Có nhiều nhất một dòng trống giữa các đoạn mã. Các lệnh trong cùng đoạn phải thể hiện được ý nghĩa của đoạn, tốt nhất nên có comment.

NênKhông nên
double AveragePrime(int[] array)
{
    int count = 0;
    double sum = 0;

    foreach (int item in array)
    {
        if (IsPrime(item))
        {
            sum += item;
            count++;
        }
    }

    return sum / count;
}
        
double AveragePrime(int[] array)
{
    int count = 0;
    double sum = 0;
    foreach (int item in array)
    {
        if (IsPrime(item))
        {
            sum += item;
            count++;
        }
    }
    return sum / count;
}
Đối với câu lệnh quá dài, phải xuống dòng sao cho toàn bộ câu lệnh không bị khuất trên màn hình IDE. Phần xuống dòng phải căn phù hợp.

NênKhông nên
void Set(string first, 
    string second, string third, 
    string fourth, string fifth, 
    string sixth)
{
    // Do some thing
}
        
void Set(string first, string se…
{
    // Do some thing
}

2.7. Phân nhóm #region

Nên sử dụng Region phân nhóm code để tiện cho việc sửa đổi, bảo trì.
Đối với class thuộc Form, nên phân nhóm các đoạn code theo cùng tính năng.

Ví dụ:
- Menu Bar
- Shortcut Key
- Event Method
-

Phân nhóm code trong một class theo cấu trúc như sau: (theo thứ tự bắt buộc, nhưng không bắt buộc có đủ tất cả các region)
- Declaration
- Property
- Constructor
- Method/Function
- Event

Tùy theo yêu cầu của các form, class và module, lập trình viên có thể chia nhỏ các Region chính trên thành các sub-region.

Ví dụ:
Region Method/Function có thể chứa các region con sau:
- Method/Function
- Public
- Overridable (trường hợp là base form/class)
- Override (trường hợp là derive form/class)
- Private
- Other

Trường hợp form hoặc class có sử dụng các component độc lập (Security, Document, MassEmail,…) thì phải tạo các Region riêng cho từng component, chứa toàn bộ code liên quan đến việc tương tác với các component đó.

3. Ngôn ngữ sử dụng

3.1. Kiểu dữ liệu C# và kiểu dữ liệu .NET

Luôn luôn sử dụng kiểu dữ liệu C# thay vì kiểu dữ liệu .NET.

NênKhông nên
int month;
double real;
string name;
ulong fact;
        
Int32 month;
Double real;
String name;
UInt64 fact;

3.2. Bổ từ truy xuất

Phải chỉ định rõ bổ từ truy xuất public, protected, private, internal, protected internal cho tất cả các trường hợp: class, interface, property, field, ...

3.3. Bẫy lỗi

Thực hiện bẫy lỗi bằng từ khóa try ... catch cho tất cả các Event và Control.
Nghiêm cấm sử dụng try ... catch để che giấu lỗi.


Tham khảo

  • Lance Hunt (2007), C# Coding Standards for .NET
  • Scott Bellware, C# Code Style Guide

4 nhận xét:

  1. Tên đồ án :Full code đồ án quản lý thẻ code c#, database
    Code : C# + database
    Tác giả:
    Mã số đồ án : M8047
    Dung lượng download : 62MB
    Mô tả :Full code đồ án quản lý thẻ code c#, database kết nối SQL server

    http://docvn.org/do-an/full-code-quan-ly-code-c-database/

    Trả lờiXóa
    Trả lời
    1. Sao mình đăng kí và trả phí rồi mà không thấy link tải vậy ?

      Xóa
  2. Cảm ơn bạn, bài viết rất hay và bổ ích cho lập trình viên
    Mời bạn ghé thăm già thiên prc

    Trả lờiXóa
  3. Cảm ơn bài viết rất hay và thú vị của bạn. Mời bạn và mọi người ghé sang Blog Dịch vụ IT BMPro đón đọc những bài viết bổ ích về kiến thức IT nhé!

    Trả lờiXóa