Абстрактные классы и интерфейсы

В абстрактных классах, как и в классах, не являющихся абстрактными, необходимо указать реализацию всех членов интерфейсов, включенных в список их базовых классов. Тем не менее, в абстрактном классе разрешается сопоставлять методы интерфейса абстрактным методам. Пример

interface IMethods
{
void F();
void G();
}

abstract class C: IMethods
{
public abstract void F();
public abstract void G();
}

В этом примере реализация интерфейса IMethods сопоставляет методы F и G абстрактным методам, которые должны быть переопределены в производных от C классах, не являющихся абстрактными.

Обратите внимание, что явные реализации члена интерфейса не могут быть абстрактными, однако в таких реализациях можно вызывать абстрактные методы. Пример

interface IMethods
{
void F();
void G();
}

abstract class C: IMethods
{
void IMethods.F() { FF(); }

void IMethods.G() { GG(); }

protected abstract void FF();

protected abstract void GG();
}

В этом примере в неабстрактными классах, производных от класса C, необходимо переопределить методы FF и GG, что обеспечит фактическую реализацию интерфейса IMethods.

Перечисления

Перечисляемый тип является особым типом значения (§4.1), который объявляет набор именованных констант.

Пример:

enum Color
{
Red,
Green,
Blue
}

объявляется перечисляемый тип с именем Color, содержащий члены Red, Green и Blue.

Объявления перечислений

Объявление перечисления объявляет новый перечисляемый тип. Объявление перечисления начинается с зарезервированного слова enum и содержит определение имени, доступности, базового типа и членов перечисления.

enum-declaration:
attributesopt enum-modifiersopt enum identifier enum-baseopt enum-body ;opt

enum-base:
: integral-type

enum-body:
{ enum-member-declarationsopt }
{ enum-member-declarations , }

Каждый перечисляемый тип имеет соответствующий целый тип, называемый базовым типом перечисляемого типа. Этот базовый тип должен иметь возможность представлять все значения перечислителя, определенные в перечислении. Объявление перечисления может явно объявлять базовый тип byte, sbyte, short, ushort, int, uint, long или ulong. Обратите внимание, что тип char не может использоваться в качестве базового типа. Объявление перечисления, которое не содержит явное объявления базового типа, имеет базовый тип int.

Пример:

enum Color: long
{
Red,
Green,
Blue
}

Здесь объявляется перечисление с базовым типом long. Разработчик может выбрать использование базового типа long, как это показано в примере, чтобы иметь возможность использования значений, которые находятся в диапазоне типа long, но не входят в диапазон типа int, или чтобы сохранить этот выбор на будущее.

Модификаторы перечисления

Объявление перечисления может, при необходимости, включать последовательность модификаторов перечисления:

enum-modifiers:
enum-modifier
enum-modifiers enum-modifier

enum-modifier:
new
public
protected
internal
private

Возникает ошибка времени компиляции, если один и тот же модификатор встречается несколько раз в объявлении перечисления.

Модификаторы объявления перечисления имеют тот же смысл, что и модификаторы объявления класса (§10.1.1). Однако обратите внимание, что в объявлении перечисления не разрешается использовать модификаторы abstract и sealed. Перечисления не могут быть абстрактными и не допускают производные типы.

Члены перечисления

Тело объявления перечисляемого типа определяет нуль или более членов перечисления, которые являются именованными константами перечисляемого типа. Два члена не могут иметь одинаковое имя.

enum-member-declarations:
enum-member-declaration
enum-member-declarations , enum-member-declaration

enum-member-declaration:
attributesopt identifier
attributesopt identifier = constant-expression

Каждый член перечисления имеет связанное с ним постоянное значение. Тип этого значения является базовым типом для содержащего его перечисления. Постоянное значение для каждого члена перечисления должно находиться в диапазоне базового типа для перечисления. Пример:

enum Color: uint
{
Red = -1,
Green = -2,
Blue = -3
}

приводит к ошибке времени компиляции, так как значения констант -1, -2 и –3 не находятся в диапазоне базового целого типа uint.

Несколько членов перечисления могут совместно использовать одно и то же связанное значение. Пример:

enum Color
{
Red,
Green,
Blue,

Max = Blue
}

Здесь показано перечисление, в котором два его члена — Blue и Max — имеют одно и то же связанное значение.

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

· если член перечисления является первым членом перечисления, объявленным в перечисляемом типе, его связанное значение равно нулю;

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

Пример:

using System;

enum Color
{
Red,
Green = 10,
Blue
}

class Test
{
static void Main() {
Console.WriteLine(StringFromColor(Color.Red));
Console.WriteLine(StringFromColor(Color.Green));
Console.WriteLine(StringFromColor(Color.Blue));
}

static string StringFromColor(Color c) {
switch (c) {
case Color.Red:
return String.Format("Red = {0}", (int) c);

case Color.Green:
return String.Format("Green = {0}", (int) c);

case Color.Blue:
return String.Format("Blue = {0}", (int) c);

default:
return "Invalid color";
}
}
}

Здесь выводятся на печать имена членов перечисления и их связанные значения. Результат выполнения примера:

Red = 0
Green = 10
Blue = 11

по следующим причинам:

· члену перечисления Red автоматически присваивается значение нуль (так как у него нет инициализатора и он является первым членом перечисления);

· члену перечисления Green явно присваивается значение 10;

· а члену перечисления Blue автоматически присваивается значение на единицу большее, чем у члена, предшествующего ему в тексте.

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

Пример:

enum Circular
{
A = B,
B
}

приводит к ошибке времени компиляции, так как объявления A и B являются циклическими. Член A зависит от B явно, а член B зависит от A неявно.

Члены перечисления именуются и имеют область видимости совершенно аналогично полям в классах. Областью видимости члена перечисления является тело содержащего его перечисляемого типа. В этой области видимости на члены перечисления можно ссылаться по их простому имени. Из всего остального кода имя члена перечисления должно уточняться именем его перечисляемого типа. У членов перечисления нет какой-либо объявленной доступности — член перечисления доступен, если доступен содержащий его перечисляемый тип.

Тип System.Enum

Тип System.Enum — это абстрактный базовый класс всех перечисляемых типов (он является особым и отличным от базового типа перечисляемого типа), и члены, унаследованные от System.Enum, доступны в любом перечисляемом типе. Преобразование упаковки (§4.3.1) возможно из любого перечисляемого типа в тип System.Enum, а также возможно преобразование распаковки (§4.3.2) из типа System.Enum в любой перечисляемый тип.

Обратите внимание, что тип System.Enum сам по себе не является перечисляемым типом. Скорее, это тип_класса, из которого производятся все перечисляемые_типы. Тип System.Enum наследуется от типа System.ValueType (§4.1.1), который, в свою очередь, наследуется от типа object. Во время выполнения значение типа System.Enum может быть равно null или являться ссылкой на упакованное значение любого перечисляемого типа.

Наши рекомендации