Вложенные определения типов

Вложенные определения типов

Перед тем как рассмотреть заключительный принцип ООП (полиморфизм), давайте обсудим технику программирования, называемую вложением типов. В C# можно определить тип (перечень, класс, интерфейс, структуру или делегат) в пределах области видимости класса или структуры. При этом вложенный ("внутренний") тип считается членом содержащего его ("внешнего") класса, с точки зрения среды выполнения ничем не отличающимся от любого другого члена (поля, свойства, метода, события и т.п.). Синтаксис, используемый для вложения типа, исключительно прост.

public class OuterClass {

 // Открытый вложенный тип могут использовать все.

 public class PublicInnerClass{}

 // Приватный вложенный тип могут использовать только члены

 // содержащего его класса.

 private class PrivateInnerClass{}

}

Синтаксис здесь ясен, но понять, почему вы можете это делать, не так просто. Чтобы прийти к пониманию этого подхода, подумайте над следующим.

• Вложение типов подобно их композиции ("has-a"), за исключением того, что вы имеете полный контроль над доступом на уровне внутреннего типа, а не содержащегося объекта.

• Ввиду того, что вложенный тип является членом класса-контейнера, этот тип может иметь доступ к приватным членам данного класса.

• Часто вложенный тип играет роль вспомогательного элемента для класса-контейнера, и его использование "внешним миром" не предполагается.

Когда некоторый тип содержит другой тип класса, он может создавать члены-переменные вложенного типа, точно так же, как для любого другого своего элемента данных. Но если вы пытаетесь использовать вложенный тип из-за границ внешнего типа, вы должны уточнить область видимости вложенного типа, указав его абсолютное имя. Изучите следующий пример программного кода.

static void Main (string[] args) {

 // Создание и использование открытого внутреннего класса. Все ОК!

 OuterClass.PublicInnerClass inner;

 inner = new OuterClass.PublicInnerClass();

 // Ошибка компиляции! Нет доступа к приватному классу.

 OuterClass.PrivateInnerClass inner2;

 inner2 = new OuterClass.PrivateInnerClass();

}

Чтобы использовать этот подход в нашем примере, предположим, что мы вложили BenefitPackage непосредственно в тип класса Employee.

// Вложение BenefitPackage.

public class Employee {

 ...

 public class BenefitPackage {

  public double ComputePayDeduction() {return 125.0;}

 }

}

Глубина вложения может быть любой. Предположим, что мы хотим создать перечень BenefitPackageLevel, указывающий различные уровни льгот, которые может выбрать работник. Чтобы программно реализовать связь между Employee, BenefitPackage и BenefitPackageLevel, можно вложить перечень так, как показано ниже.

// Employee содержит BenefitPackage.

public class Employee {

 // BenefitPackage содержит BenefitPackageLevel.

 public class BenefitPackage {

  public double ComputePayDeduction() {return 125.0;}

  public enum BenefitPackageLevel {

   Standard, Gold, Platinum

  }

 }

}

С учетом отношений вложении обратите внимание на то, как приходится иcпользовать этот перечень.

Static void Main(string[] args) {

 // Создание переменной BenefitPackageLevel.

 Employee.BenefitPackage.BenefitPackageLevel myBenefitLevel = Employee.BenefitPackage.BenefitPackageLevel.Platinum;

 …

}