Các static
từ khóa có thể là một chút khó khăn cho người mới để nắm bắt. Mục đích chính của nó là xác định một thành viên lớp không thuộc về bất kỳ trường hợp đơn lẻ nào của lớp, mà thay vào đó là chính lớp đó.
Không đi sâu vào chi tiết, C # (và Java) thực thi một cách cứng nhắc lý tưởng hướng đối tượng rằng tất cả mã và dữ liệu phải thuộc về một đối tượng và do đó bị giới hạn về phạm vi, khả năng hiển thị và thời gian tồn tại. Đó thường là cách thực hành tốt nhất ở bất cứ nơi nào nguyên lý cơ bản của một đối tượng đại diện cho một số điều trong thế giới thực. Tuy nhiên, không phải lúc nào cũng vậy; đôi khi những gì bạn cần là một hàm hoặc biến mà bạn có thể nhận được từ bất kỳ nơi nào trong mã, mà không yêu cầu bạn chuyển một tham chiếu đến một đối tượng có chứa nó và với sự đảm bảo rằng dữ liệu bạn đang xem hoặc thay đổi là chính xác mọi người khác là xử lý, và không phải là một bản sao của nó thuộc về một thể hiện khác của một đối tượng.
Hành vi như vậy đã có sẵn trong C và C ++ dưới dạng hàm hoặc biến "toàn cầu", không được gói gọn trong một đối tượng. Vì vậy, như một sự thỏa hiệp, C # và Java hỗ trợ "phạm vi tĩnh", một nửa điểm giữa mã thực sự toàn cầu không có đối tượng cha và các thành viên thể hiện phạm vi giới hạn.
Bất kỳ "thành viên mã" nào (hàm, thuộc tính, trường) được khai báo là static
thuộc phạm vi của dòng đầu tiên của main()
hàm và không để lại cho đến khi main()
hàm kết thúc. Trong tiếng Anh đơn giản, một thành viên tĩnh tồn tại và có thể được sử dụng miễn là chương trình đang chạy. Ngoài ra, các thành viên tĩnh được gọi bằng cách gọi chúng là thành viên của chính loại đó, không phải là thành viên của bất kỳ một thể hiện nào của loại đó:
public class Foo
{
public int MyInt {get;set;} //this is an "instance member"
public static int MyStaticInt {get;set;} //this is a "static member"
}
...
var myFoo = new Foo();
myFoo.MyInt = 5; //valid
myFoo.MyStaticInt = 5; //invalid; MyStaticInt doesn't belong to any one Foo
Foo.MyInt = 5; //invalid; MyInt only has meaning in the context of an instance
Foo.MyStaticInt = 2; //valid
Điều này làm cho các thành viên tĩnh hiển thị với bất kỳ mã nào có kiến thức về loại, cho dù họ có biết về bất kỳ trường hợp nào của nó hay không.
Để trả lời câu hỏi của bạn, lợi ích chính của việc đánh dấu một cái gì đó là tĩnh là nó sẽ hiển thị ở bất cứ nơi nào loại chính nó được biết, bất kể mã tiêu thụ có hoặc có thể lấy một thể hiện của đối tượng chứa. Cũng có một chút lợi ích hiệu suất ; bởi vì phương thức nằm trong phạm vi tĩnh, nó chỉ có thể truy cập các thành viên tĩnh khác (cùng lớp hoặc các lớp khác) và bất cứ điều gì được truyền vào dưới dạng tham số. Do đó, bộ thực thi không phải giải quyết bất kỳ tham chiếu nào đến thể hiện hiện tại của đối tượng chứa, vì thông thường nó sẽ phải cho một phương thức cá thể để cung cấp thông tin trạng thái cụ thể theo ngữ cảnh.
Toàn bộ các lớp cũng có thể được đánh dấu tĩnh; bằng cách làm như vậy, bạn nói với trình biên dịch rằng khai báo lớp sẽ chỉ bao gồm các thành viên tĩnh và do đó không thể được khởi tạo. Đây là một cách dễ dàng để đảm bảo có một và chỉ một bản sao của một đối tượng trong bộ nhớ; làm cho lớp và mọi thứ trong đó tĩnh. Tuy nhiên, rất hiếm khi đây là giải pháp tốt nhất cho nhu cầu như vậy. Trong tình huống yêu cầu chính xác một bản sao của một tập hợp dữ liệu, "đơn lẻ" thường được ủng hộ thay thế; đây là một lớp không tĩnh, sử dụng một bộ truy cập tĩnh và một hàm tạo không công khai để cung cấp quyền truy cập vào một thể hiện của chính nó. Về mặt lý thuyết, một singleton cung cấp nhiều lợi ích tương tự của một lớp hoàn toàn tĩnh, nhưng với khả năng bổ sung để sử dụng lớp theo cách hướng đối tượng, dựa trên cá thể.