У C #, яка різниця між загальнодоступними, приватними, захищеними та не мають модифікатора доступу?


728

Всі мої студентські роки я використовую public, і хотів би знати різницю між public, privateі protected?

Крім того, що staticробити на відміну від того, щоб нічого не мати?

Відповіді:


1007

Доступ до модифікаторів

Від docs.microsoft.com :

public

Тип або член може отримати доступ будь-яким іншим кодом у тій же збірці або іншій збірці, на яку посилається.

private

Тип або член можуть отримати доступ лише за кодом у тому ж класі або структурі.

protected

Доступ до типу або члена можна отримати лише за допомогою коду того ж класу або структури, або у похідному класі.

private protected (додано в C # 7.2)

Доступ до типу або члена можна отримати лише за допомогою коду того ж класу або структури, або у похідному класі з тієї ж збірки, але не з іншої збірки.

internal

Тип або член може отримати доступ будь-яким кодом у тій же збірці, але не з іншої збірки.

protected internal

Тип або член можна отримати за допомогою будь-якого коду в одній збірці або будь-якого похідного класу в іншій збірці.

Якщо не встановлено модифікатор доступу, використовується модифікатор доступу за замовчуванням. Отже, завжди існує певна форма модифікатора доступу, навіть якщо вона не встановлена.

static модифікатор

Статичний модифікатор класу означає, що клас не може бути екземпляром і всі його члени статичні. Статичний член має одну версію, незалежно від того, скільки створено екземплярів цього типу.

Статичний клас в основному такий же, як нестатичний клас, але є одна відмінність: статичний клас не може бути зовнішньо інстанційним. Іншими словами, ви не можете використовувати нове ключове слово для створення змінної типу класу. Оскільки змінної примірника немає, ви отримуєте доступ до членів статичного класу, використовуючи саме ім’я класу.

Однак є така річ, як статичний конструктор . Будь-який клас може мати один із них, включаючи статичні класи. Вони не можуть бути викликані безпосередньо і не можуть мати параметри (крім будь-яких параметрів типу у самому класі). Статичний конструктор викликається автоматично для ініціалізації класу до створення першого екземпляра або посилання будь-яких статичних членів. Виглядає так:

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

    public static string Bar { get; set; }
}

Статичні класи часто використовуються як сервіси, ви можете їх використовувати так:

MyStaticClass.ServiceMethod(...);

17
І ви можете мати статичні методи в нестатичних класах, правда?
Іван Бубріскі

14
Так, вони поводилися б так само, як і в моєму прикладі.
mbillard

7
Що в цьому контексті означає термін "збірка"?
Джонатан Глісон

1
@gotoVoid Невірно, що ви шукали в Google. Відповідно до MSDN , захищений внутрішній означає, що "тип або член може отримати доступ будь-яким кодом у складі, в якому він оголошений, або з похідного класу в іншій збірці".
Кевін

2
Яка різниця між захищеними та приватними захищеними? Для мене це звучить як те саме ..
goofyui

161

Графічний огляд (короткий виклад)

Видимість

Оскільки статичні класи запечатані, вони не можуть бути успадковані (за винятком Object), тому захищене ключове слово недійсне для статичних класів.



Якщо типово не встановити модифікатор доступу спереду, дивіться тут:
видимість за замовчуванням для класів та членів C # (поля, методи тощо)?

Не вкладений

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

Вкладено:

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

Крім того, є вони запечатані-ключове слово, що робить клас не успадкованим.
Також у VB.NET ключові слова часом бувають різними, тому тут шпаргалка:

VB проти CS еквіваленти


1
@ ᴀʀᴜn BᴇrtiL: Ви впевнені? Похідний клас в іншій збірці?
Стефан Штайгер

вивести клас в одній асамблеї ми можемо, різного ми не можемо. Я думав, ти мав на увазі, як в одній асамблеї ...
Арун Бертіл

1
@ ᴀʀᴜn BᴇrtiL: Хм, правда, це насправді має бути вилуплено.
Стефан Штайгер

1
Я думаю, що в діаграмі є помилка. Якщо внутрішній використовується для класу, клас може бути отриманий іншим класом у цій же збірці. Крім того, якщо внутрішній модифікатор використовується у властивості, до цього властивості можна також отримати доступ у похідному класі в тій же збірці. Можливо, діаграма правильна, оскільки є "так" під "містить збірку", але її можна неправильно зрозуміти, оскільки є "ні" під "похідними класами".
АГ.

160

Загальнодоступний - якщо ви можете бачити клас, то ви можете бачити метод

Приватне - Якщо ви є частиною класу, ви можете бачити метод, інакше ні.

Захищений - такий самий, як приватний, плюс цей метод також можуть бачити всі нащадки .

Статичний (клас) - Пам’ятаєте різницю між «Класом» та «Об’єктом»? Забудьте про все це. Вони однакові з "статичними" ... клас - це єдиний екземпляр сам по собі.

Статичний (метод) - кожного разу, коли ви використовуєте цей метод, він матиме систему відліку, незалежну від фактичного примірника класу, до якого він входить.


1
Невже ви не можете мати статичні методи в нестатичному класі?
Іван Бубріскі

1
Так, але я говорив про статичний клас. Я додав окремий запис для опису статичних методів. Дякую за улов.
JosephStyons

2
"Об'єкт" може бути не надто хорошим терміном, коли йдеться про C #, оскільки базовим типом для всіх класів є System.Object . "Екземпляр" буде кращим словом, або "об'єктом" (малим "O").
Лесдерід

@lesderid 'object' - псевдонім "System.Object", його використання також може бути заплутаним. "Примірник" буде краще, я думаю :)
dpp

ті ж правила застосовуються і до структур.
gsharp

35

Повторне розміщення дивовижних діаграм із цієї відповіді .

Ось всі модифікатори доступу в діаграмах Венна, від більш обмежувальних до більш розбещених:

private:
введіть тут опис зображення

private protected: - додано в C # 7.2
введіть тут опис зображення

internal:
введіть тут опис зображення

protected:
введіть тут опис зображення

protected internal:
введіть тут опис зображення

public:
введіть тут опис зображення


24

введіть тут опис зображення

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
Я не бачу, що ця відповідь додає до багатьох інших відповідей за останні п’ять років.
Джон Сондерс

4
Це лише просте пояснення. Оскільки інші відповіді трохи заплутані і наполовину відповіли :)
Narottam Goyal

4
@John Saunders: Він розмежовує, розділяючи видимість для похідного класу між тим класом, який знаходиться в одному і тому ж класі, який знаходиться в іншому складі. Крім того, він забезпечує, як він дійшов до цієї інформації, показуючи свій зразок коду. Тож насправді додає до інших відповідей. Його некромантизація, ймовірно, була спровокована моїм коментарем у моїй відповіді.
Стефан Штайгер

2
"Отриманий клас у різних збірках" - це додає значення діаграмі, вже наведеній в іншій відповіді. Різниця корисна особливо у випадку "захищеного внутрішнього"
Нірман

Я вважаю цю діаграму найлегшою для мене для розуміння. Щоб зберегти цей струм (з C # 7.2), додати Private Protected, це було б: той самий клас = Yes, однакова збірка, похідний клас = Yes, однакова збірка, будь-який клас = NO, інша збірка, похідний клас = NO, інша збірка, будь-який клас = NO. Ще однією пропозицією було б не перемикати порядок слів protected internal, оскільки це порушує пневмоніку з відповіді @ user1810087
Intrastellar Explorer

22

Щодо питання нічого

  • Типи простору імен за замовчуванням є внутрішніми
  • Будь-який член типу, включаючи вкладені типи, за замовчуванням є приватними

15

Ще один візуальний підхід поточного модифікатора доступу (C # 7.2). Сподіваємось, схема допомагає запам'ятати її легше
(натисніть на зображення для інтерактивного перегляду.)

інтерактивні модифікатори доступу svg

Зовні всередині

Якщо ви намагаєтеся запам’ятати двоскладні модифікатори доступу, пам’ятайте про зовні .

  • приватний захищений : приватний зовні (одна і та ж збірка), захищений всередині (та ж збірка)
  • захищений внутрішній : захищений зовні (одна і та ж збірка) внутрішній всередині (той самий вузол)

11

Хм.

Дивіться тут: Модифікатори доступу .

Коротко:

Public надає методу чи типу повну видимість з інших типів / класів.

Приватний дозволяє тільки тип, що містить приватний метод / змінну, доступ до приватного методу / змінної (зауважте, що вкладені класи також мають доступ до приватних методів / змінних, що містять класи).

Захищений схожий на приватний, окрім похідних класів, також можна отримати доступ до захищених методів.

"Нічого" - еквівалент VB.NET нулю. Хоча якщо ви маєте на увазі "нічого", що означає "немає модифікатора доступу", це залежить, хоча дуже грубе правило (безумовно, в C #) полягає в тому, що якщо ви чітко не вказуєте модифікатор доступу, метод / змінну декларація зазвичай настільки ж обмежена, наскільки це може бути. тобто

public class MyClass
{
    string s = "";
}

фактично те саме, що:

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

Зв'язана стаття MSDN надасть повний опис, коли не існує чітко вказаного модифікатора доступу.


8

публічний - до нього може бути доступ будь-хто.
приватний - доступ до нього можна отримати лише з класу, до якого він входить.
захищений - доступ до нього може бути доступний лише з класу або будь-якого об'єкта, який успадковує клас.

Ніщо не нагадує нуля, але в VB.
Статичний означає, що у вас є один екземпляр цього об'єкта, метод для кожного примірника цього класу.


4

ммм ...

Статичний означає, що ви можете отримати доступ до цієї функції, не маючи примірника класу.

Ви можете отримати доступ безпосередньо з визначення класу.


4

Статус Приватний вказує на те, що до змінних можуть бути доступні лише об'єкти одного класу. Захищений статус поширює цей доступ і на нащадків класу.

"З наведеної вище таблиці ми можемо побачити відмінність між приватними та захищеними ... я думаю, що обидва однакові .... так, у чому потреба в цих двох окремих командах"

Перевірте посилання MSDN для отримання додаткової інформації


3

Ці модифікатори доступу вказують, де бачать ваші члени. Ви, напевно, повинні прочитати це. Візьміть посилання, подане IainMH, як вихідну точку.

Статичні члени - один на клас, а не один на примірник.


3

Уважно стежте за доступністю своїх занять. Публічні та захищені класи та методи за замовчуванням доступні для всіх.

Крім того, Microsoft не дуже чітко показує модифікатори доступу (загальнодоступні, захищені тощо), коли створюються нові класи в Visual Studio. Отже, будьте добре уважні та подумайте про доступність свого класу, оскільки це двері до внутрішніх справ вашого впровадження.


2

Я думаю, що це пов'язано з хорошим дизайном OOP. Якщо ви розробник бібліотеки, ви хочете приховати внутрішню роботу своєї бібліотеки. Таким чином, згодом ви можете змінити внутрішню роботу бібліотеки. Таким чином, ви ставите своїх членів та помічників як приватні, а лише методи інтерфейсу є загальнодоступними. Методи, які слід перезаписати, слід захищати.


1

C # має загалом 6 модифікаторів доступу:

приватний : Член, оголошений з цією доступністю, може бути видимим у складі містить тип, він не видно жодним похідним типам, іншим типам у тій же збірці або типам, що не містять збірки, що містить. тобто доступ обмежений лише типом, що містить тип.

захищено : учасник, оголошений з цією доступністю, може бути видимим у межах типів, що походять від утримуючого типу, у складі, що містить, і типів, похідних від типу, що містить, поза вмістуючої збірки. тобто доступ обмежений похідними типами, що містять тип.

Внутрішній : Член, оголошений з цією доступністю, може бути видимим у складі, що містить цього члена, він не видно жодному зібранню за межами містить збірку. тобто доступ обмежений лише тим, що містить збірку.

Внутрішньо захищений : учасник, оголошений з цією доступністю, може бути видимим у межах типів, що походять від типу, що міститься, всередині або поза ним, він містить також будь-які типи, що містять збірку. тобто доступ обмежений типом, що містить збірки або похідні типи.

public : Член, оголошений з цією доступністю, може бути видимим у складі, що містить цього члена, або будь-якій іншій збірці, на яку посилається, що містить збірку. тобто доступ не обмежений.

C # 7.2 додає новий рівень доступності:

приватний захищений : учасник, оголошений з цією доступністю, може бути видимим у межах типів, похідних від цього типу, що міститься в складі, що містить. Він не видно для будь-яких типів, що не походять із вмісту, що міститься, або поза його вмістом. тобто доступ обмежений похідними типами всередині містить збірку.

Джерело, включаючи зразок коду нового приватного захищеного модифікатора доступу


Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.