Preprocessor Directives trong C# là gì?

C# preprocessor directives là gì? Trong C# chúng ta vẫn hay thấy #if, #region, #error… đó là những preprocessor directives hay còn gọi là chỉ thị tiền xử lý. Về ý tưởng, khái niệm preprocessor trong C# là tương đồng với khái niệm reprocessor trong C/C++. Hôm nay tôi sẽ chia sẻ về preprocessor directives trong C#.

 

1) Định nghĩa

Preprocessor directives là một chỉ thị tiền xử lý – tức là những lệnh giúp điều hướng hoặc xác định nội dung code trong quá trình biên dịch code. Preprocessor directives trong C# có những đặc điểm sau đây:

  • Nó không phải là lệnh của ngôn ngữ lập trình nên sẽ không kết thúc bằng “;
  • Khác với preprocessor directives trong C, trong C# bạn không thể dùng preprocessor directives để định nghĩa macro.
  • Tất cả các preprocessor directives luôn bắt đầu bởi dấu “#
  • Các preprocessor directives phải được viết trên cùng một line

Ngữ cảnh để sử dụng preprocessor directives: Ví dụ tôi viết một ứng dụng Console khá đơn giản để phân tích nội dung một trang HTML. Chức năng chính của ứng dụng này là lấy nội dụng html từ một trang web chỉ định và phân tích nội dụng dựa trên một số tiêu chí về SEO. Trong quá trình code, dĩ nhiên sẽ có nhu cầu DEBUG hay Unit test; và chúng ta sẽ có một số khó khăn sau:

  1. Phụ thuộc vào kết nối internet khi lấy data từ wensite online.
  2. Mất nhiều thời gian cho việc tải data trong quá trình Unit test hay debug.

Vậy tôi muốn khi debug hay unit test, nội dụng cần phân tích sẽ chỉ là đọc từ một tập tin html hay từ local website là đủ. Khi thật sự là sản phẩm cuối cùng tôi mới có nhu cầu lấy data từ internet. Để làm được yêu cầu trên chúng ta sẽ nghĩ đến việc sử dụng preprocessor directives. #if DEBUG

Sau đây là một số preprocessor directives và ý nghĩa của chúng.

#define Định nghĩa một chỉ thị/chỉ dẫn
#undef Huỷ một chỉ thị/chỉ dẫn nếu đã được định nghĩa trước đó
#if Kiểm tra một chỉ thị/chỉ định có được định nghĩa hay chưa
#else Block code nghịch của #if.
#elif Bổ xung điều kiện cho #if
#endif Kết thúc block code của #if
#line Chỉ định số thứ tự của dòng (line code) trong tập tin, thường dùng để mô tả dòng bị lỗi hay một thông điệp cho dòng code
#error Xuất lỗi trong quá trình complile. Mặc định số dòng là nơi bạn xuất lỗi. Có thể dùng #line để thay đổi giá trị số dòng, tập tin.
#warning Xuất cảnh báo trong quá trình complile. Mặc định số dòng là nơi bạn xuất lỗi. Có thể dùng #line để thay đổi giá trị số dòng, tập tin.
#region Đánh dấu block code
#endregion Kết thúc đánh dấu block code

Các preprocessor directives được chia thành 3 nhóm.
Conditional compilation: Cho phép chỉ định định nội dung biên dịch.

  • #if
  • #else
  • #elif
  • #endif
  • #define
  • #undef

Errors , Warnings , Line & pragma: Cho phép thể hiện các thông báo về lỗi, cảnh báo và một số thông tin khác

  • #warning
  • #error
  • #line
  • #pragma

Region:Cho phép tạo hay đánh dấu block code

  • #region
  • #endregion

2) Cách dùng

#define và #undef: Chỉ được dùng ở đầu tập tin *.cs và trước mọi dòng code. #define có phạm vi chỉ trong một file.


#define VERSION_1_0_0
#undef VERSION_1_0_0

using System;

namespace Preprocessor_Directives
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Do something here.");
        }
    }
}

Nếu dùng #define và #undef xen lẫn giữa các dòng code, bạn sẽ nhận lỗi tương tự sau:

#if, #else, #elif và #endif: Dùng để thay đổi nội dung cần biên dịch.

#define VERSION_3_0_0
#define DEBUG
#define UNIT_TEST
using System;

namespace Preprocessor_Directives
{
    class Program
    {
        static void Main(string[] args)
        {
            string ver = string.Empty;
#if VERSION_1_0_0
            ver = "1.0.0";
#elif VERSION_2_0_0
            ver = "2.0.0";
#elif DEBUG || UNIT_TEST
            Console.WriteLine("App is running in debug mode or Unit test.");
#else
            Console.WriteLine("Please define version.");
#endif

            Console.WriteLine($"Version: {ver}");
        }
    }
}

Khi bạn sử dụng #if cùng với #elif, nếu điều kiện đầu tiên được thõa mản nghĩa là các điều kiện sau đó sẽ được bỏ qua nếu chúng cũng thõa mãn.

#warning and #error: Dùng để xuất cảnh báo hoặc lỗi của source code.

#define VERSION_1_0_0
#define DEBUG
#define UNIT_TEST
using System;

namespace Preprocessor_Directives
{
    class Program
    {
        static void Main(string[] args)
        {
#if UNIT_TEST && DEBUG
#warning "You are using Unit test in DEBUG mode."
#endif

#if VERSION_1_0_0 && UNIT_TEST
#error "Version 1.0.0 does not allow Unit test."
#endif

            Console.WriteLine("Do something here.");
        }
    }
}

Bạn sẽ nhận được lỗi ngay trong editor khi dùng #error hay cảnh báo khi dùng #warning.

Lỗi khi build.

#line: Được dùng để thay đổi giá trị số dòng hay tên file cho việc mô tả lỗi. Ví dụ chúng ta dùng #line ở file Program để mô tả lỗi ở một file HtmlHelper.cs.

HtmlHelper.cs

#undef DEBUG
using System;

namespace Preprocessor_Directives
{
    public static class HtmlHelper
    {
        public static string GetHtml(string url)
        {
#if DEBUG
            return @"<html></html>";
#else
            throw new NotImplementedException("This function not available.");
#endif
        }
    }
}

Program.cs

#define VERSION_1_0_0
#undef DEBUG
using System;

namespace Preprocessor_Directives
{
    class Program
    {
        static void Main(string[] args)
        {
            string html = string.Empty;

#if !DEBUG
#line 13 "HtmlHelper.cs"
#error "Some function not available now."
#endif

            Console.WriteLine("Do something here.");
        }
    }
}

Lỗi khi build.

#pragma: Dùng để hướng dẫn trình biên dịch. Ví dụ sau đây là cách disable cảnh báo “The field “Program.html” is never used“.

Kết quả khi dùng #pragma

#region và #endregion: Dùng để gom block code.

3) Nâng cao

Chúng ta đã biết #define có phạm vi trong một tập tin *.cs thế nên nếu bạn cần sử dụng 1 chỉ thị đánh dấu cho nhiều nơi bạn sẽ phải define ở nhiều tập tin khác nhau. Đó là một nhược điểm lớn. Nhưng đôi khi bạn thấy rằng bạn không hề define cho chỉ định DEBUG nhưng bạn vẫn có thể sử dụng được ở mọi file. Đó là vì một số chỉ định được diefine trong phạm vi toàn cục ví dụ như DEBUG.

Vậy các chỉ thị toàn cục được define ở đâu. Bạn chọn project và chuột phải, chọn property.

Để define thêm các chỉ thị riêng, bạn thêm vào mục “Conditional compilation symbols”.

Hoặc mở file project để thêm.

Bài viết có tham khảo từ một số nguồn từ internet.

Phạm Tuân

Cấu hình log4net và logging.adapter trong code c#
Mã OTP Hoạt Động Thế Nào Và Cách Tạo Mã OTP
Tạo bộ cài Visual Studio 2019 Bản Quyền Offline
Hãy bình luận trực tiếp ở đây để được trả lời nhanh hơn. 4 bình luận.

Trả lời