Вкладені класи. Вкладені статичні класи. Оголошення та використання вкладених класів. Приклади

Вкладені класи. Вкладені статичні класи. Оголошення та використання вкладених класів. Приклади


Зміст



1. Поняття вкладеного класу. Загальна форма оголошення вкладеного класу

У мові C# будь-який клас у своїй реалізації може містити оголошення іншого класу. Клас, що оголошується в межах фігурних дужок іншого класу, називається вкладеним класом.

У найпростішому випадку, загальна форма оголошення вкладеного класу в класі має вигляд:

// клас, що містить в реалізації оголошення іншого класу
class Outer
{
  // поля та методи класу Outer
  // ...

  class Inner
  {
    // поля та методи класу Inner
    // ...
  }

  // поля та методи класу Outer
  // ...
}

де

  • Outer – ім’я класу, який містить в собі оголошення іншого класу з іменем Inner;
  • Inner – ім’я класу, який оголошується в класі Outer.

Класи Outer та Inner можуть містити різні специфікатори, які визначають доступ (private, protected, public) чи інші властивості класу (static, sealed і т.д.).

 

2. Як виглядає загальна форма оголошення об‘єкту вкладеного класу?

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

Якщо вкладений клас оголошено як не private-клас, то створення екземпляру цього класу має такий вигляд:

Outer.Inner objInner = new Outer.Inner();

де

  • Outer – імʼя зовнішнього класу, в якому оголошується вкладений клас Inner;
  • Inner – імʼя вкладеного класу, який оголошений в межах фігурних дужок класу Outer;
  • objInner – імʼя обʼєкту (екземпляру) класу, який створюється;
  • Outer.Inner() – імʼя конструктора за замовчуванням, що викликається для створення обʼєкту класу. Якщо у класі Inner реалізовано інші параметризовані конструктори, то цей виклик може бути іншим.

 

3. Які модифікатори доступу можуть застосовуватись до вкладених класів?

До вкладених класів можуть застосовуватись такі самі модифікатори доступу як і до звичайних – невкладених класів:

  • private. У цьому випадку вкладений клас є видимий в межах фігурних дужок { } зовнішнього класу;
  • public. У цьому випадку вкладений клас є доступний в межах зовнішнього класу, з екземпляру зовнішнього класу, з успадкованого класу та за межами збірки;
  • protected. У цьому випадку клас є доступний в межах зовнішнього класу та з методів успадкованих класів;
  • internal. Вкладений клас є доступний в межах збірки і недоступний за межами збірки;
  • protected internal. Вкладений клас може бути доступний з методів зовнішнього класу, методів успадкованих класів або недоступний з методів за межами поточної збірки.

Дія модифікаторів така сама як і у випадку з членами даних (методами) класу.

 

4. Приклад, що демонструє використання класів з різними модифікаторами доступу

У прикладі демонструється оголошення та доступ до вкладених класів, що містять різні модифікатори доступу.

Оголошується клас Outer, який містить:

  • дві внутрішні public-змінні з іменами d та sd. Змінна sd оголошена як статична;
  • внутрішній метод GetInner1(), який демонструє доступ до private-класу Inner1;
  • вкладений клас Inner1, який оголошено як private;
  • вкладений клас Inner2, який оголошено як public;
  • вкладений клас Inner3, який оголошено як internal;
  • вкладений клас Inner4, який оголошено як protected;
  • вкладений клас Inner5, який оголошено як protected internal.

У кожному з вкладених класів оголошуються:

  • одна нестатична змінна цілого типу;
  • одна статична змінна цілого типу.

Лістинг класу Outer наступний:

// клас Outer містить 5 вкладених класів
public class Outer
{
  // внутрішні змінні класу Outer
  public int d;
  static public int sd;

  // доступ до private-класу Inner1 з внутрішнього методу класу
  public Inner1 GetInner1()
  {
    Inner1 i1 = new Inner1(); // створити екземпляр класу Inner1

    // доступ до члена даних класу Inner1 через екземпляр класу
    i1.d1 = 25;

    // доступ до статичного члена вкладеного класу Inner1
    Inner1.sd1 = 30;

    return i1;
  }

  // private-вкладений клас Inner1
  private class Inner1
  {
    public int d1;
    public static int sd1;
  }

  // public-вкладений клас Inner2
  public class Inner2
  {
    public int d2;
    public static int sd2;
  }

  // internal-вкладений клас Inner3
  internal class Inner3
  {
    public int d3;
    public static int sd3;
  }

  // protected-вкладений клас Inner4
  protected class Inner4
  {
    public int d4;
    public static int sd4;
  }

  // protected-internal вкладений клас Inner5
  protected internal class Inner5
  {
    public int d5;
    public static int sd5;
  }
}

Використання вкладених класів в деякому методі може бути таким:

// Використання вкладених класів Outer.Inner1, Outer.Inner2, Outer
// 1. Оголосити об'єкт класу Outer
Outer o = new Outer();
o.d = 300; // доступ до внутрішньої змінної через екземпляр класу Outer
Outer.sd = 230; // доступ до статичної змінної

// 2. Немає доступу до private-класу Inner1 через екземпляр класу Outer
// Outer.Inner1 i; - помилка, клас Inner1 оголошено як private

// 3. Оголосити об'єкт public-класу Inner2
Outer.Inner2 i2 = new Outer.Inner2();
i2.d2 = 440;
Outer.Inner2.sd2 = 500; // доступ до статичної змінної

// 4. Оголосити об'єкт internal-класу Inner3
Outer.Inner3 i3 = new Outer.Inner3();
i3.d3 = 100;
Outer.Inner3.sd3 = 400; // доступ до статичної змінної

// 5. Оголосити об'єкт protected-класу можна тільки з успадкованих класів
// Outer.Inner4 i4; - помилка

// 6. Оголосити об'єкт protected-internal-класу можна
Outer.Inner5 i5 = new Outer.Inner5();
i5.d5 = 200;
Outer.Inner5.sd5 = -100;

Як видно з вищенаведеного коду, створювати обʼєкти можна тільки для класів Inner2, Inner3, Inner5. Щоб створити обʼєкт protected-класу Inner4, потрібно оголосити інший клас, який успадковує клас Outer, наприклад:

// клас Outer2 є успадкованим від класу Outer
class Outer2 : Outer
{
  // у методі успадкованого класу є доступ до protected-класу Inner4
  void SomeMethod()
  {
    // створити екземпляр класу Outer.Inner4
    Inner4 i4 = new Inner4(); // працює
    i4.d4 = 23; // доступ через екземпляр класу
    Inner4.sd4 = 330; // доступ до статичної змінної
  }
}

Даний приклад також показує, що вкладений private-клас приховує доступ до оголошеної в ньому статичної змінної з методів інших класів. Так само, приховує доступ і вкладений protected-клас.

 

5. Оголошення та використання статичного вкладеного класу у нестатичному. Приклад

У нестатичному класі може бути оголошений статичний клас (з ключовим словом static). Це означає, що статичний клас даного класу є унікальним єдиним ресурсом. Доступ до елементів статичного класу здійснюється безпосередньо за іменем статичного класу, перед яким через крапку слідує імʼя (імена) зовнішнього класу (класів).

Приклад. Оголошується клас Outer, який містить оголошення вкладеного статичного (static) класу Inner. У класі Inner оголошується статична внутрішня public-змінна. Текст класу Outer наступний:

// клас Outer - нестатичний
public class Outer
{
  // внутрішні змінні класу Outer
  public int d;
  static public int sd;

  // статичний вкладений клас Inner
  public static class Inner
  {
    // тільки статичні змінні можуть оголошуватись у статичному класі
    public static int sd; // статична внутрішня змінна класу Inner
  }
}

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

// доступ до статичної змінної статичного класу Outer.Inner
Outer.Inner.sd = 45;

// створити об'єкт (екземпляр) класу Outer
Outer o = new Outer();
o.d = 30; // є доступ до змінних екземпляру класу через об'єкт
Outer.sd = 102; // доступ до статичної змінної класу Outer

// створювати об'єкт статичного класу неможна
//Outer.Inner i = new Outer.Inner(); - це є помилка!

 

6. Чи можна у статичному класі оголосити нестатичний вкладений клас?

Так, можна. У статичному класі можна оголошувати нестатичні вкладені класи. Однак, у статичному класі неможна оголошувати нестатичні змінні та методи.

Наприклад. Нехай оголошується статичний клас Outer, який містить реалізацію нестатичного класу Inner

// клас Outer - статичний
public static class Outer
{
  // внутрішні змінні класу Outer
  // тільки статичні екземпляри можна оголошувати в статичному класі
  // public int d; - помилка!
  static public int sd;

  // нестатичний вкладений клас Inner - може оголошуватись в статичному класі
  public class Inner
  {
    public int d; // нестатична змінна
    public static int sd; // статична внутрішня змінна класу Inner
  }
}

Використання класів Outer та Outer.Inner може бути, наприклад, таким:

// використання нестатичного класу у статичному класі
// доступ до статичної змінної sd класу Outer.Inner
Outer.Inner.sd = 230;

// доступ до статичної змінної sd класу Outer
Outer.sd = 132;

// Неможна створювати екземпляр (об'єкт) статичного класу
// Outer o = new Outer(); // помилка, оскільки Outer - статичний клас

// створити екземпляр вкладеного класу Outer.Inner
Outer.Inner i = new Outer.Inner();
i.d = 323; // доступ до нестатичної змінної d класу Outer.Inner

 

7. Приклад оголошення та використання статичного вкладеного класу в іншому статичному класі

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

Нехай задано оголошення статичних класів Outer та Inner:

// клас Outer - статичний
public static class Outer
{
  // тільки статичні екземпляри можна оголошувати в статичному класі
  static public int sd;

  // статичний вкладений клас Inner - може оголошуватись в статичному класі
  public static class Inner
  {
    // тут тільки статичні елементи
    public static int sd; // статична внутрішня змінна класу Inner
  }
}

Використання статичних елементів цих класів може бути таким:

// використання статичного класу у статичному класі
// доступ до статичної змінної sd класу Outer.Inner
Outer.Inner.sd = 140;

// доступ до статичної змінної sd класу Outer
Outer.sd = 110;

// Неможна створювати екземпляр (об'єкт) статичного класу
// Outer o = new Outer(); // помилка, оскільки Outer - статичний клас

 


Зв’язані теми