Trong C #, sự khác biệt giữa công khai, riêng tư, được bảo vệ và không có công cụ sửa đổi truy cập là gì?


728

Tất cả các năm học đại học của tôi, tôi có được sử dụng public, và muốn biết sự khác biệt giữa public, privateprotected?

Ngoài ra những gì staticlàm trái ngược với không có gì?

Câu trả lời:


1008

Sửa đổi truy cập

Từ docs.microsoft.com :

public

Loại hoặc thành viên có thể được truy cập bởi bất kỳ mã nào khác trong cùng một hội đồng hoặc một hội đồng khác tham chiếu nó.

private

Loại hoặc thành viên chỉ có thể được truy cập bằng mã trong cùng một lớp hoặc cấu trúc.

protected

Loại hoặc thành viên chỉ có thể được truy cập bằng mã trong cùng một lớp hoặc cấu trúc, hoặc trong một lớp dẫn xuất.

private protected (được thêm vào C # 7.2)

Loại hoặc thành viên chỉ có thể được truy cập bằng mã trong cùng một lớp hoặc cấu trúc, hoặc trong một lớp dẫn xuất từ ​​cùng một hội đồng, nhưng không phải từ một hội đồng khác.

internal

Loại hoặc thành viên có thể được truy cập bởi bất kỳ mã nào trong cùng một hội đồng, nhưng không phải từ một hội đồng khác.

protected internal

Loại hoặc thành viên có thể được truy cập bởi bất kỳ mã nào trong cùng một cụm hoặc bởi bất kỳ lớp dẫn xuất nào trong một cụm khác.

Khi không có công cụ sửa đổi truy cập nào được đặt, công cụ sửa đổi truy cập mặc định sẽ được sử dụng. Vì vậy, luôn có một số hình thức sửa đổi truy cập ngay cả khi nó không được đặt.

static bổ nghĩa

Công cụ sửa đổi tĩnh trên một lớp có nghĩa là lớp không thể được khởi tạo và tất cả các thành viên của nó là tĩnh. Một thành viên tĩnh có một phiên bản bất kể có bao nhiêu phiên bản loại kèm theo của nó được tạo.

Một lớp tĩnh về cơ bản giống như một lớp không tĩnh, nhưng có một điểm khác biệt: một lớp tĩnh không thể được khởi tạo bên ngoài. Nói cách khác, bạn không thể sử dụng từ khóa mới để tạo một biến của loại lớp. Vì không có biến đối tượng, bạn truy cập các thành viên của lớp tĩnh bằng cách sử dụng tên lớp.

Tuy nhiên, có một thứ như là một hàm tạo tĩnh . Bất kỳ lớp nào cũng có thể có một trong số này, bao gồm các lớp tĩnh. Chúng không thể được gọi trực tiếp & không thể có các tham số (ngoài bất kỳ tham số loại nào trên chính lớp đó). Một constructor tĩnh được gọi tự động để khởi tạo lớp trước khi phiên bản đầu tiên được tạo hoặc bất kỳ thành viên tĩnh nào được tham chiếu. Trông như thế này:

static class Foo()
{
    static Foo()
    {
        Bar = "fubar";
    }

    public static string Bar { get; set; }
}

Các lớp tĩnh thường được sử dụng làm dịch vụ, bạn có thể sử dụng chúng như vậy:

MyStaticClass.ServiceMethod(...);

17
Và bạn có thể có các phương thức tĩnh trong các lớp không tĩnh, phải không?
John Bubriski

14
Vâng, họ sẽ cư xử giống như trong ví dụ của tôi.
mbillard

7
Thuật ngữ "lắp ráp" có nghĩa là gì trong bối cảnh này?
Jonathan Gl lý

1
@gotoVoid Bất cứ điều gì bạn tìm kiếm trên Google đều không chính xác. Theo MSDN , nội bộ được bảo vệ có nghĩa là, "loại hoặc thành viên có thể được truy cập bởi bất kỳ mã nào trong hội đồng mà nó được khai báo hoặc từ bên trong một lớp dẫn xuất trong một tổ hợp khác."
Kevin

2
Sự khác biệt giữa bảo vệ và bảo vệ tư nhân là gì? Đối với tôi, âm thanh của cả hai đều giống nhau ..
goofyui

161

Tổng quan về đồ họa (tóm tắt ngắn gọn)

Hiển thị

các lớp tĩnh được niêm phong, chúng không thể được kế thừa (ngoại trừ từ Object), vì vậy từ khóa được bảo vệ là không hợp lệ trên các lớp tĩnh.



Đối với các mặc định nếu bạn không đặt công cụ sửa đổi truy cập ở phía trước, xem tại đây:
Khả năng hiển thị mặc định cho các lớp và thành viên C # (trường, phương thức, v.v.)?

Không lồng nhau

enum                              public
non-nested classes / structs      internal
interfaces                        internal
delegates in namespace            internal
class/struct member(s)            private
delegates nested in class/struct  private

Lồng nhau:

nested enum      public
nested interface public
nested class     private
nested struct    private

Ngoài ra, có từ khóa kín, làm cho một lớp không kế thừa.
Ngoài ra, trong VB.NET, các từ khóa đôi khi khác nhau, vì vậy đây là một cheat-sheet:

Tương đương VB so với CS


1
@ ᴀʀᴜn BᴇrtiL: Bạn có chắc không? Một lớp dẫn xuất trong một hội đồng khác nhau?
Stefan Steiger

lớp dẫn xuất trong cùng một hội đồng chúng ta có thể, khác nhau chúng ta không thể. Tôi nghĩ bạn có ý nghĩa như trong cùng một hội nghị ...
Arun Beces

1
@ ᴀʀᴜn BᴇrtiL: Hmm, phải, điều này thực sự nên được nở.
Stefan Steiger

1
Tôi nghĩ rằng có một lỗi trong sơ đồ. Nếu nội bộ được sử dụng cho một lớp, lớp này có thể được dẫn xuất bởi một lớp khác trong cùng một tổ hợp. Ngoài ra nếu công cụ sửa đổi nội bộ được sử dụng trên một thuộc tính, thuộc tính này cũng có thể được truy cập trong lớp dẫn xuất trong cùng một cụm. Có lẽ sơ đồ là chính xác bởi vì có "có" trong "chứa lắp ráp", nhưng nó có thể bị hiểu nhầm bởi vì có "không" dưới "các lớp dẫn xuất".
À.

160

Công khai - Nếu bạn có thể thấy lớp, thì bạn có thể thấy phương thức

Riêng tư - Nếu bạn là một phần của lớp, thì bạn có thể xem phương thức, nếu không thì không.

Được bảo vệ - Giống như Riêng tư, cộng với tất cả con cháu cũng có thể thấy phương thức.

Tĩnh (lớp) - Ghi nhớ sự phân biệt giữa "Lớp" và "Đối tượng"? Quên tất cả đi. Chúng giống nhau với "tĩnh" ... lớp là trường hợp một và duy nhất của chính nó.

Tĩnh (phương thức) - Bất cứ khi nào bạn sử dụng phương thức này, nó sẽ có một khung tham chiếu độc lập với thể hiện thực của lớp mà nó là một phần của.


1
Bạn có thể có các phương thức tĩnh trong một lớp không tĩnh không?
John Bubriski

1
Vâng, nhưng tôi đã nói về một lớp tĩnh. Tôi đã thêm một mục riêng để mô tả các phương thức tĩnh. Cảm ơn đã bắt.
JosephStyons

2
'Đối tượng' có thể không phải là một thuật ngữ tốt ở đây khi nói về C #, vì loại cơ sở cho tất cả các lớp là System.Object . 'Trường hợp' sẽ là một từ tốt hơn, hoặc 'đối tượng' (chữ thường 'O').
lesderid

@lesderid 'object' là bí danh của 'System.Object', sử dụng nó cũng có thể gây nhầm lẫn. 'dụ' sẽ tốt hơn, tôi đoán vậy :)
dpp

quy tắc tương tự áp dụng cho các cấu trúc.
gsharp

35

Đăng lại các sơ đồ tuyệt vời từ câu trả lời này .

Dưới đây là tất cả các sửa đổi truy cập trong sơ đồ Venn, từ hạn chế hơn đến lăng nhăng hơn:

private:
nhập mô tả hình ảnh ở đây

private protected: - được thêm vào C # 7.2
nhập mô tả hình ảnh ở đây

internal:
nhập mô tả hình ảnh ở đây

protected:
nhập mô tả hình ảnh ở đây

protected internal:
nhập mô tả hình ảnh ở đây

public:
nhập mô tả hình ảnh ở đây


24

nhập mô tả hình ảnh ở đây

using System;

namespace ClassLibrary1
{
    public class SameAssemblyBaseClass
    {
        public string publicVariable = "public";
        protected string protectedVariable = "protected";
        protected internal string protected_InternalVariable = "protected internal";
        internal string internalVariable = "internal";
        private string privateVariable = "private";
        public void test()
        {
            // OK
            Console.WriteLine(privateVariable);

            // OK
            Console.WriteLine(publicVariable);

            // OK
            Console.WriteLine(protectedVariable);

            // OK
            Console.WriteLine(internalVariable);

            // OK
            Console.WriteLine(protected_InternalVariable);
        }
    }

    public class SameAssemblyDerivedClass : SameAssemblyBaseClass
    {
        public void test()
        {
            SameAssemblyDerivedClass p = new SameAssemblyDerivedClass();

            // NOT OK
            // Console.WriteLine(privateVariable);

            // OK
            Console.WriteLine(p.publicVariable);

            // OK
            Console.WriteLine(p.protectedVariable);

            // OK
            Console.WriteLine(p.internalVariable);

            // OK
            Console.WriteLine(p.protected_InternalVariable);
        }
    }

    public class SameAssemblyDifferentClass
    {
        public SameAssemblyDifferentClass()
        {
            SameAssemblyBaseClass p = new SameAssemblyBaseClass();

            // OK
            Console.WriteLine(p.publicVariable);

            // OK
            Console.WriteLine(p.internalVariable);

            // NOT OK
            // Console.WriteLine(privateVariable);

            // Error : 'ClassLibrary1.SameAssemblyBaseClass.protectedVariable' is inaccessible due to its protection level
            //Console.WriteLine(p.protectedVariable);

            // OK
            Console.WriteLine(p.protected_InternalVariable);
        }
    }
}

 using System;
        using ClassLibrary1;
        namespace ConsoleApplication4

{
    class DifferentAssemblyClass
    {
        public DifferentAssemblyClass()
        {
            SameAssemblyBaseClass p = new SameAssemblyBaseClass();

            // NOT OK
            // Console.WriteLine(p.privateVariable);

            // NOT OK
            // Console.WriteLine(p.internalVariable);

            // OK
            Console.WriteLine(p.publicVariable);

            // Error : 'ClassLibrary1.SameAssemblyBaseClass.protectedVariable' is inaccessible due to its protection level
            // Console.WriteLine(p.protectedVariable);

            // Error : 'ClassLibrary1.SameAssemblyBaseClass.protected_InternalVariable' is inaccessible due to its protection level
            // Console.WriteLine(p.protected_InternalVariable);
        }
    }

    class DifferentAssemblyDerivedClass : SameAssemblyBaseClass
    {
        static void Main(string[] args)
        {
            DifferentAssemblyDerivedClass p = new DifferentAssemblyDerivedClass();

            // NOT OK
            // Console.WriteLine(p.privateVariable);

            // NOT OK
            //Console.WriteLine(p.internalVariable);

            // OK
            Console.WriteLine(p.publicVariable);

            // OK
            Console.WriteLine(p.protectedVariable);

            // OK
            Console.WriteLine(p.protected_InternalVariable);

            SameAssemblyDerivedClass dd = new SameAssemblyDerivedClass();
            dd.test();
        }
    }
}

1
Tôi không thấy câu trả lời này thêm vào những câu trả lời nào khác trong năm năm qua.
John Saunders

4
Đây chỉ là một lời giải thích đơn giản. Vì các câu trả lời khác hơi khó hiểu và một nửa đã trả lời :)
Narottam Goyalty

4
@ John Saunders: Nó khác biệt bằng cách tách biệt khả năng hiển thị cho một lớp dẫn xuất giữa lớp đó giống nhau và lớp đó nằm trong một hội đồng khác. Thêm vào đó anh ta cung cấp cách anh ta có được thông tin đó bằng cách hiển thị mã mẫu của mình. Vì vậy, nó thực sự thêm vào các câu trả lời khác. Necromance của anh ấy có lẽ được kích hoạt bởi nhận xét của tôi trong câu trả lời của tôi.
Stefan Steiger

2
"Lớp phái sinh trong hội đồng khác nhau" - điều này làm tăng giá trị cho biểu đồ đã được đưa ra trong một câu trả lời khác. Sự khác biệt rất hữu ích, đặc biệt là trong trường hợp "được bảo vệ nội bộ"
Nirman

Tôi thấy biểu đồ này là dễ hiểu nhất đối với tôi. Để giữ dòng điện này (với C # 7.2), để thêm vào Private Protected, nó sẽ là: cùng một lớp = Yes, cùng một tổ hợp, lớp dẫn xuất = Yes, cùng một tổ hợp, bất kỳ lớp nào = NO, lắp ráp khác nhau, lớp dẫn xuất = NO, lắp ráp khác nhau, bất kỳ lớp nào = NO. Một đề xuất bổ sung cũng sẽ không được chuyển đổi thứ tự từ protected internal, vì điều này phá vỡ pneumonic từ câu trả lời của @ user1810087
Intrastellar Explorer

22

Liên quan đến câu hỏi Không có gì

  • Các loại không gian tên là nội bộ theo mặc định
  • Bất kỳ loại thành viên, bao gồm các loại lồng nhau là riêng tư theo mặc định

15

Một cách tiếp cận trực quan khác của công cụ sửa đổi truy cập hiện tại (C # 7.2). Hy vọng lược đồ giúp ghi nhớ dễ dàng hơn
(nhấp vào hình ảnh để xem tương tác.)

sửa đổi truy cập tương tác svg

Bên ngoài bên trong

Nếu bạn đấu tranh để nhớ các công cụ sửa đổi truy cập hai từ, hãy nhớ bên ngoài - bên trong .

  • private bảo vệ : private bên ngoài (cùng một hội đồng) được bảo vệ bên trong (cùng một hội đồng)
  • bảo vệ bên trong : bảo vệ bên ngoài (cùng lắp ráp) bên trong (cùng lắp ráp)

11

Hừm.

Xem tại đây: Bộ điều chỉnh truy cập .

Tóm lại:

Công khai cung cấp phương thức hoặc kiểu hiển thị đầy đủ từ các loại / lớp khác.

Riêng tư chỉ cho phép kiểu chứa phương thức riêng / truy cập biến vào phương thức / biến riêng (lưu ý rằng các lớp lồng nhau cũng có quyền truy cập vào các lớp / phương thức riêng của lớp chứa).

Được bảo vệ tương tự như riêng tư ngoại trừ các lớp dẫn xuất cũng có thể truy cập các phương thức được bảo vệ.

"Không có gì" là VB.NET tương đương với null. Mặc dù nếu bạn đang đề cập đến "nothing" có nghĩa là "không có công cụ sửa đổi truy cập", thì điều đó còn tùy thuộc, mặc dù một quy tắc rất thô sơ (chắc chắn trong C #) là nếu bạn không chỉ định rõ ràng công cụ sửa đổi truy cập, thì phương thức / biến khai báo thường là hạn chế như nó có thể được. I E

public class MyClass
{
    string s = "";
}

có hiệu quả tương tự như:

public class MyClass
{
    private string s = "";
}

Bài viết MSDN được liên kết sẽ cung cấp một mô tả đầy đủ khi không có công cụ sửa đổi truy cập được chỉ định rõ ràng.


8

công cộng - có thể được truy cập bởi bất cứ ai ở bất cứ đâu.
private - chỉ có thể được truy cập từ trong với nó, nó là một phần của.
được bảo vệ - chỉ có thể được truy cập từ trong trong lớp hoặc bất kỳ đối tượng nào kế thừa khỏi lớp.

Không có gì giống như null nhưng trong VB.
Tĩnh có nghĩa là bạn có một thể hiện của đối tượng đó, phương thức cho mọi thể hiện của lớp đó.


4

Ừm ...

Tĩnh có nghĩa là bạn có thể truy cập hàm đó mà không cần có một thể hiện của lớp.

Bạn có thể truy cập trực tiếp từ định nghĩa lớp.


4

Một trạng thái của Private chỉ ra rằng các biến chỉ có thể được truy cập bởi các đối tượng của cùng một lớp. Tình trạng được bảo vệ mở rộng quyền truy cập để bao gồm cả hậu duệ của lớp.

"từ bảng trên, chúng ta có thể thấy sự trì hoãn giữa riêng tư và được bảo vệ ... tôi nghĩ cả hai đều giống nhau .... vì vậy cần gì cho hai lệnh riêng biệt đó"

Kiểm tra liên kết MSDN để biết thêm thông tin


3

Những sửa đổi truy cập xác định nơi các thành viên của bạn được nhìn thấy. Bạn có lẽ nên đọc nó lên. Lấy liên kết được đưa ra bởi IainMH làm điểm bắt đầu.

Các thành viên tĩnh là một cho mỗi lớp và không phải là một ví dụ.


3

Cẩn thận xem khả năng tiếp cận của các lớp học của bạn. Các lớp và phương thức công khai và được bảo vệ theo mặc định có thể truy cập được cho mọi người.

Ngoài ra, Microsoft không quá phô trương trong việc hiển thị các sửa đổi truy cập (từ khóa công khai, được bảo vệ, v.v.) khi các lớp mới trong Visual Studio được tạo. Vì vậy, hãy chăm sóc cẩn thận và suy nghĩ về khả năng tiếp cận của lớp bạn vì đó là cánh cửa cho các bộ phận thực hiện của bạn.


2

Tôi nghĩ rằng nó có liên quan đến thiết kế OOP tốt. Nếu bạn là nhà phát triển thư viện, bạn muốn ẩn hoạt động bên trong của thư viện. Bằng cách đó, bạn có thể sửa đổi hoạt động bên trong thư viện của mình sau này. Vì vậy, bạn đặt các thành viên và phương thức trợ giúp của mình ở chế độ riêng tư và chỉ các phương thức giao diện là công khai. Các phương pháp nên được ghi đè nên được bảo vệ.


1

C # có tổng cộng 6 công cụ sửa đổi truy cập:

private : Thành viên được khai báo với khả năng truy cập này có thể hiển thị trong loại có chứa, nó không hiển thị với bất kỳ loại dẫn xuất nào, các loại khác trong cùng một cụm hoặc các loại bên ngoài lắp ráp có chứa. tức là, truy cập chỉ giới hạn ở loại chứa.

được bảo vệ : Thành viên được khai báo với khả năng truy cập này có thể được nhìn thấy trong các loại có nguồn gốc từ loại có chứa trong cụm chứa và các loại có nguồn gốc từ loại có chứa bên ngoài lắp ráp có chứa. tức là, truy cập bị giới hạn trong các loại dẫn xuất của loại chứa.

bên trong : Thành viên được khai báo với khả năng truy cập này có thể được nhìn thấy trong hội đồng có chứa thành viên này, nó không thể nhìn thấy đối với bất kỳ hội đồng nào bên ngoài tổ hợp có chứa. tức là, truy cập chỉ giới hạn trong việc chứa lắp ráp.

bảo vệ bên trong : Thành viên được khai báo với khả năng truy cập này có thể hiển thị trong các loại có nguồn gốc từ loại có chứa bên trong hoặc bên ngoài cụm chứa, nó cũng hiển thị với bất kỳ loại nào trong cụm chứa. tức là, truy cập bị giới hạn trong việc chứa các kiểu lắp ráp hoặc dẫn xuất.

công cộng : Thành viên được khai báo với khả năng truy cập này có thể hiển thị trong hội đồng có chứa thành viên này hoặc bất kỳ hội đồng nào khác tham chiếu đến tổ hợp có chứa. tức là truy cập không giới hạn.

C # 7.2 đang thêm một cấp độ tiếp cận mới:

bảo vệ riêng tư : Thành viên được khai báo với khả năng truy cập này có thể được nhìn thấy trong các loại có nguồn gốc từ loại có chứa này trong hội đồng chứa. Nó không thể nhìn thấy đối với bất kỳ loại không xuất phát từ loại có chứa, hoặc bên ngoài lắp ráp có chứa. tức là, quyền truy cập bị giới hạn ở các loại dẫn xuất trong cụm chứa.

Nguồn bao gồm mã mẫu của công cụ sửa đổi truy cập được bảo vệ riêng tư mới


0

Tất cả các mô tả của người sửa đổi truy cập cho C #

nhập mô tả hình ảnh ở đây

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.