Nil trước đây được biết đến như là con trỏ rỗng (như null bên các ngôn ngữ khác).
Nếu bạn cố gắng truy cập đến con trỏ nil (nil pointer), bạn sẽ nhận được lỗi vi phạm truy cập Access violation.
Trong lập trình hướng đối tượng, nil là giá trị được gán đến cho object chưa được thực thể hóa.
var
aList: TStringList;
begin
// aList đang có giá trị nil
end;
Khi bạn cố gắng truy cập đến field, method hoặc property của nil object, một ngoại lệ (exception) sẽ được ném ra, tên là Access Violation at $123AB3D gì đó. Điều này gây ra lỗi và có thể làm chương trình bị ngừng nếu không có biện pháp xử lý phù hợp (Xem bài Xử lý ngoại lệ)
Bạn có thể lợi dụng nil để kiểm tra xem một đối tượng có thể được sử dụng hay không, bằng cách so sánh nó với nil.
if aList <> nil then
begin
... // Do something with aList
end;
Hoặc dùng hàm Assigned cũng có ý nghĩa tương đương. Hàm này trả về true nếu object khác nil, ngược lại object là nil thì trả về false
if Assigned(aList) = true then
begin
... // Do something with aList
end;
Khi một object được giải phóng bằng Free, nó thực sự không bị đặt thành nil. Nó vẫn còn trỏ đến một vùng nhớ đã cấp trước đó.
Điều này có một bất lợi, bạn sẽ không biết object có thể sử dụng hay không. Như đã đề cập ở cuối phần 1, có một kĩ thuật kiểm tra object có thể sử dụng bằng cách so sánh với nil.
Nếu object khác nil, nó có thể sử dụng được. Nhưng rõ ràng, object đã được Free (không sử dụng được) không được đặt thành nil, như thế chúng ta sẽ vô tình truy cập vào object đã bị xóa (dẫn đến lỗi Access Violation).
Unit System.SysUtils cung cấp một thủ tục để làm việc này. Thay vì viết.
// Có thể gây lỗi
Obj.Free;
Bạn có thể viết thành như sau để tránh lỗi
Obj.Free;
Obj := nil;
Hoặc dùng hàm FreeAndNil để ngắn gọn hơn
FreeAndNil(Obj);
Free là phương thức an toàn hơn hàm hủy Destroy. Về cơ bản, hàm Free sẽ gọi Destroy nếu đối tượng khác nil.
procedure TObject.Free;
begin
if Self <> nil then
Self.Destroy;
end;
Lời khuyên là bạn nên hạn chế sử dụng destroy vì sẽ gây lỗi. Lấy ví dụ, Destroy không kiểm tra đối tượng có nil hay không. Nếu destroy vào đối tượng nil thì chương trình sẽ bị lỗi.
Như mã ví dụ ở phần 3, bạn thấy có sử dụng biến Self. Bạn sẽ thắc mắc nó ở đâu ra. Nó chưa được khai báo mà ?
procedure TObject.Free;
begin
if Self <> nil then
Self.Destroy;
end;
Mình đã đánh dấu lại bằng chữ in nghiêng. Self là đại diện cho object của class hiện tại. Class hiện tại là class của phương thức, ở đây là phương thức Free.
Khái niệm Self khá giống với this bên C++.
Bình thường thì không cần viết Self.Destroy mà chỉ cần viết Destroy là delphi tự hiểu, nhưng trong 1 số trường hợp cần dùng Self.
A. So sánh object hiện tại với nil hoặc object khác
Ví dụ so sánh với nil như ở trên. Sau đây là ví dụ khác.
procedure TSimpleClass.DoSomeThing;
begin
if Self = Obj1 then
ShowMessage('Object 1 is doing something');
end;
B. Khi tham số method trùng tên với field
Điển hình nhất là hàm tạo, có những tham số trùng tên với các field trong class. Khi đó, ta viết Self.Field để phân biệt.
type
THuman = class
Name: string;
Age: Byte;
public
constructor Create(Name: string; Age: Byte);
end;
constructor THuman.Create(Name: string; Age: Byte);
begin
Self.Name := Name;
Self.Age := Age;
end;
Chúng ta viết Self.Name và Self.Age để phân biệt với Name và Age của tham số method.