Lập trình C#

Hàm hủy Destructor trong C#

Hàm hủy Destructor trong C#
Được viết bởi Minh Hoàng

Series lập trình C#, ngôn ngữ lập trình hiện đại và mạnh mẽ.

Hàm huỷ destructor là một hàm thành viên của lớp (phương thức) có chức năng ngược với hàm tạo constructor. Hàm huỷ được gọi trước khi giải phóng (xoá bỏ) một đối tượng để thực hiện một số công việc có tính “dọn dẹp” trước khi đối tượng được huỷ bỏ, ví dụ như giải phóng một vùng nhớ mà đối tượng đang quản lý, xoá đối tượng khỏi màn hình nếu như nó đang hiển thị,…

Xem thêm: Hàm tạo (constructor) trong C#.

– Nếu trong lớp không định nghĩa hàm huỷ, thì một hàm huỷ mặc định không làm gì cả được phát sinh. Đối với nhiều lớp thì hàm huỷ mặc định là đủ, và không cần đưa vào một hàm huỷ mới.

– Một Destructor trong C# là một hàm thành viên đặc biệt:

  • Có tên giống với tên class, và có thêm dấu ngã ~ ở trước. Chẳng hạn: ~Car() , ~Student(),…
  • Không có giá trị trả về, có thể có hoặc không có tham số.

– Cú pháp khai báo:

~TênLớp()
{
	// cleanup statements
}

– Ví dụ (*) :

// Khai báo destructor
~Car()
{
	// cleanup statements
}

Destructor có một số đặc điểm như sau:

  • Được gọi đến trước khi một đối tượng bị thu hồi. Rất hữu ích để giải phóng tài nguyên bộ nhớ trước khi kết thúc chương trình.
  • Không được chỉ định phạm vi truy cập.
  • Không được kế thừa (inherited) hoặc nạp chồng (overloaded).
  • Mỗi lớp chỉ có duy nhất một phương thức destructor.
  • Destructor không thể được gọi từ đối tượng, mà nó sẽ được gọi ngầm một cách tự động.
  • Destructor chỉ có trong kiểu class, mà không có trong kiểu struct.

Lưu ý:

  • Empty destructors should not be used.
  • Nếu destructor là rỗng (empty – không có nội dung) thì không nên sử dụng. Vì khi một class có chứa phương thức destructor thì khi đó một entry sẽ được tạo trong queue (hàng đợi) của Finalize.
  • Khi destructor được gọi thì Garbage Collector (GC) được gọi để xử lý. Do đó mà gây ra một tổn thất không cần thiết về hiệu suất của chương trình.
  • Vì vậy nếu không có xử lý gì đặc biệt để giải phóng vùng nhớ thì không khai báo phương thức destructor.

Destructor ngầm định gọi Finalize trên base class (lớp cơ sở, lớp cha) của đối tượng (object). Do đó, code minh họa destructor ở trên (*) sẽ được implicitly translated (chuyển đổi ngầm định) như sau:

protected override void Finalize()
{
	try
	{
		// cleanup statements
	}
	finally
	{
		base.Finalize();
	}
}
Object.Finalize Method()

Cho phép một object free resources và thực hiện các operations cleanup khác, trước khi nó bị thu hồi bởi GC (Garbage Collection)

– Syntax C#:

protected virtual void Finalize()

– Remarks:

  • Phương thức Finalize() được sử dụng để thực hiện các hoạt động cleanup trên resources không được quản lý (unmanaged), không được sử dụng đang được nắm giữ bởi current object, trước khi object is destroyed.
  • Access modifier của phương thức là protected, do đó chỉ có thể access thông qua class này hoặc thông qua một derived class (lớp dẫn xuất, lớp con).

– Điều này có nghĩa là method Finalize() sẽ được gọi đệ quy cho tất cả các instances trong một chuỗi có quan hệ kế thừa (inherited): từ derived class cuối cùng nhất đến base class đầu tiên nhất (from the most-derived class – to the least-derived class). Để hiểu hơn về điều này thì chúng ta cùng xem ví dụ sau đây:

using System;

namespace MinhHoangBlog
{
    class Program
    {
        static void Main(string[] args)
        {
			// Chỉ khởi tạo đối tượng của class Third
			Third t = new Third();

            // Thực hiện các xử lý......
            
            // Giải phóng object
            t = null;

            GC.Collect();
            Console.Read();
        }
    }

	class First
	{
		// Constructor
		public First()
		{
			System.Diagnostics.Trace.WriteLine("First's object was created.");
		}

		// Destructor
		~First()
		{
			System.Diagnostics.Trace.WriteLine("First's destructor was called.");
		}
	}

	class Second : First
	{
		// Constructor
		public Second()
		{
			System.Diagnostics.Trace.WriteLine("Second's object was created.");
		}

		// Destructor
		~Second()
		{
			System.Diagnostics.Trace.WriteLine("Second's destructor was called.");
		}
	}

	class Third : Second
	{
		// Constructor
		public Third()
		{
			System.Diagnostics.Trace.WriteLine("Third's object was created.");
		}

		// Destructor
		~Third()
		{
			System.Diagnostics.Trace.WriteLine("Third's destructor was called.");
		}
	}
}
Kết quả chương trình

Kết quả chương trình

– Ở ví dụ trên tạo ra 3 classes mà thực hiện một chuỗi các thừa kế (chain of inheritance):

  • class First là lớp cơ sở (base class),
  • class Second kế thừa từ class First,
  • và class Third kế thừa từ class Second.

– Trong mỗi class First, Second, Third sẽ tạo ra một destructor, trong hàm main() chỉ tạo instance của class dẫn xuất cuối cùng là class Third (tức là the most-derived class).

– Khi chạy chương trình, thì phương thức destructor của 2 class First, Second cũng được gọi một cách tự động trong chuỗi kế thừa, và theo thứ tự: the most-derived class => the least-derived class, có nghĩa là được destructor lần lượt là: [destructor của class Third] => [destructor của class Second] => [destructor của class First].

Cảm ơn bạn đã theo dõi. Đừng ngần ngại hãy cùng thảo luận với chúng tôi!

Giới thiệu

Minh Hoàng

Xin chào, tôi là Hoàng Ngọc Minh, hiện đang làm BrSE, tại công ty Toyota, Nhật Bản. Những gì tôi viết trên blog này là những trải nghiệm thực tế tôi đã đúc rút ra được trong cuộc sống, quá trình học tập và làm việc. Các bài viết được biên tập một cách chi tiết, linh hoạt để giúp bạn đọc có thể tiếp cận một cách dễ dàng nhất. Hi vọng nó sẽ có ích hoặc mang lại một góc nhìn khác cho bạn[...]

Translate »