Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Объектно-ориентированное программирование.-6

.pdf
Скачиваний:
6
Добавлен:
05.02.2023
Размер:
4.5 Mб
Скачать

ку компилятора. Параметр /reference (краткая форма /r) указывает компилятору C# импортировать сведения типа public из указанного файла сборки в текущий проект. Синтаксис:

csc.exe /reference:[<псевдоним>=]<имя файла> ...

csc.exe /reference:<имя файла> ...

4.1.3.2. Внешние псевдонимы

Параметр /reference позволяет задавать псевдоним сборки, однако, подключая стандартные сборки, компилятор по умолчанию этого не делает (рис. 4.4). Как видно в окне вывода данных о построении проекта, ни один псевдоним не указан.

Рис. 4.4 – Протокол построения проекта

Это можно сделать самостоятельно в окне свойств (рис. 4.5). После этого синтаксис использования псевдонимов в тексте программы будет следующим:

extern alias <псевдоним>;

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

<псевдоним>::<элемент сборки>

Например, зададим сборке System псевдоним «X». Теперь корректен следующий код:

extern alias X;

using System;

namespace AliasSample

{

class Program

251

{

static int Main()

{

X::System.Collections.Generic.Stack<int> stack;

return 0;

}

}

}

Это может потребоваться в случае использования нестандартных сборок или при конфликтах имен элементов сборок.

Рис. 4.5 – Окно свойств

Как мы видим на рис. 4.5, все сборки по умолчанию имеют псевдоним, которому соответствует ключевое слово global. Его можно использовать как обычный псевдоним. Все объекты, объявленные вне пространства имен, и все пространства имен верхнего уровня входят в глобальное безымянное пространство имен, имеющее псевдоним global:

struct S { }

namespace AliasSample

{

class Program

{

static int Main()

{

252

global::System.Collections.Generic.IList<int> list; global::AliasSample.Program prog;

global::S s;

return 0;

}

}

}

Пример: Samples\4.1\4_1_3_alias.

253

§ 4.2. Описание класса

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

Синтаксис описания класса следующий:

[<атрибуты>] [<модификаторы>] class <идентификатор> [<параметры типа>] [: <список наследования>] [<ограничения параметров типа>]

"{"

[<тело класса>]

"}" [;]

Итак, в описании класса участвуют следующие конструкции:

атрибуты (см. § 5.4);

модификаторы (п. 4.2.1);

параметры типа (§ 5.1);

список наследования (§ 4.6);

ограничения параметров типа (§ 5.1);

тело класса (п. 4.2.2).

4.2.1. Модификаторы класса

Имеющиеся модификаторы классов доступа перечислены в табл. 4.1.

 

Табл. 4.1 – Модификаторы доступа в языке C#

 

 

Модификатор

Описание

 

 

abstract

Объявляет абстрактный класс, экземпляры которого со-

 

здавать запрещено. Не может быть запечатанным (sealed)

 

 

internal

Доступ к классу не ограничен в пределах данной про-

 

граммы

 

 

new

Допускается только во вложенных классах. Он определя-

 

ет сокрытие классом унаследованного члена с таким же

 

именем

 

 

 

254

partial

Объявляет разделяемый класс, отдельные части которого

 

могут быть описаны в разных местах программы

 

 

private

Допускается только во вложенных классах. Доступ к

 

классу предоставляется только для класса, в котором он

 

описан

 

 

protected

Допускается только во вложенных классах. Доступ к

 

классу предоставляется только для класса, в котором он

 

описан, и для его потомков

 

 

protected

Допускается только во вложенных классах. Доступ к

internal

классу не ограничен в пределах данной программы, в

 

 

противном случае предоставляется только для класса, в

 

котором он описан, и его потомков

 

 

public

Доступ к классу не ограничен

 

 

sealed

Объявляет запечатанный класс, для которого запрещено

 

создание производных классов

 

 

static

Объявляет статический класс. Запрещено создавать его

 

экземпляры, а все члены должны быть статическими. Не

 

может быть запечатанным или абстрактным, не может

 

наследоваться от других классов

 

 

unsafe

Весь код, описанный в классе, является небезопасным.

 

 

Пример:

abstract class AbsCls { } // ОК

abstract sealed class AbsSealed { } // Ошибка

new class XXX { } // Ошибка

class ZZZ1

{

public class XXX { } public class YYY { }

}

class ZZZ2 : ZZZ1

{

public class XXX { } // Предупреждение public new class YYY { } // ОК

}

public class Pub { } // ОК protected class Prot { } // Ошибка private class Priv { } // Ошибка internal class Int { } // ОК

protected internal class PInt { } // Ошибка

255

class Cls

{

public class Pub { } protected class Prot { } private class Priv { } internal class Int { }

protected internal class PInt { }

}

sealed class QQQ { } // ОК class WWW : QQQ { } // Ошибка

static abstract class SAC { } // Ошибка static sealed class SSC { } // Ошибка static class SC : Cls { } // Ошибка

static class StatClass

{

public void Pub() { }

//

Ошибка

 

protected static void

Prot()

{ }

// Ошибка

public static

void

Met()

{ }

// ОК

public

static

StatClass()

{ } //

Ошибка

static

StatClass()

{ } //

ОК

 

 

}

class Program

{

static int Main()

{

AbsCls abs = new AbsCls(); // Ошибка

Pub

pub1

= new

Int

int1

= new

Cls.Pub

cpub

= new

Cls.Prot

cprot = new

Cls.Priv

tpriv

= new

Cls.Int

tint

= new

Cls.PInt

tpint = new

StatClass stat = new

Pub(); // ОК Int(); // ОК Cls.Pub(); // ОК

Cls.Prot(); // Ошибка Cls.Priv(); // Ошибка Cls.Int(); // ОК Cls.PInt(); // ОК StatClass(); // Ошибка

StatClass.Met(); // ОК return 0;

}

}

Как мы уже говорили, для классов, объявленных в пространстве имен, по умолчанию подразумевается модификатор доступа internal. Для классов, объявленных в теле другого класса – private.

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

partial class PartCls

{

public void X() { }

}

partial class PartCls

256

{

public void Y() { }

}

class Program

{

static int Main()

{

PartCls part = new PartCls(); part.X(); // ОК

part.Y(); // ОК return 0;

}

}

Для структур запрещены модификаторы abstract, sealed и static, все остальное верно и для них.

Пример: Samples\4.2\4_2_1_modifiers.

4.2.2. Члены класса

Объявление класса может содержать объявления:

1.типов (п. 4.2.5);

2.констант (п. 4.3.1);

3.полей (п. 4.3.2);

4.методов (§ 4.4);

5.конструкторов экземпляров (п. 4.4.2);

6.статических конструкторов (п. 4.4.2);

7.деструкторов (п. 4.4.3);

8.свойств (п. 4.5.1);

9.индексаторов (п. 4.5.2);

10.операторов (п. 4.7.3);

11.событий (§ 4.8);

Общий синтаксис описания членов класса следующий:

[<атрибуты>] [<модификаторы>] <описание>

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

Табл. 4.2 – Модификаторы членов класса

Модификатор

Описание

Члены

 

 

 

abstract

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

4,8,9,11

 

 

 

 

257

 

const

Член является константой

2(*)

event

Описывает событие

11(*)

extern

Член имеет внешнюю реализацию

4-11

 

 

 

internal

Член доступен во всей программе

1-5,8,9,11

 

 

 

new

Сокрытие унаследованного члена

1-4,8,9,11

 

 

 

override

Перегрузка унаследованного члена

4,8,9,11

 

 

 

partial

Разделяемый метод класса

4

 

 

 

protected

Член доступен в классе и его потомках

1-5,8,9,11

 

 

 

private

Член доступен только в классе

1-5,8,9,11

 

 

 

public

Член доступен отовсюду

1-5,8,9,10(*),11

 

 

 

readonly

Поле только для чтения

3

 

 

 

sealed

Запрет дальнейшей перегрузки члена

1(**),4,8,9,11

 

 

 

static

Статический член

1(**),3,4,6(*),8,10(*),11

 

 

 

unsafe

Небезопасный контекст

1(***),3-11

 

 

 

virtual

Виртуальный член

4,8,9,11

 

 

 

volatile

Поле, не проходящее оптимизацию

3

 

 

 

Примечания: (*) – обязательное условие; (**) – если вложенный тип описывает класс; (***) – если вложенный тип не является перечислением.

Абстрактный член в классе имеет описание, но не имеет реализации. Т.е. класс, содержащий абстрактный член, является незавершенным. Он также должен быть абстрактным. Абстрактные члены предназначены для перегрузки классами-потомками.

С локальными переменными-константами мы уже знакомились в § 3.1,

вклассе также могут быть объявлены константы-члены класса. Модификатор extern указывает, что реализация члена класса находится

вне программы, обычно в DLL (см. § 5.5) или внешней сборке. Его нельзя использовать совместно с модификатором abstract.

О модификаторах доступа public, internal, protected и private мы уже говорили, все сказанное для классов верно и для их членов. Аналогично для модификатора new.

Модификатор virtual применяется для описания виртуального члена. Виртуальный член может быть перегружен в классе-потомке. От абстрактного члена он отличается тем, что имеет реализацию (тело). Модификатор override используется для перегрузки абстрактных и виртуальных членов в

258

классах-потомках. Модификатор sealed запрещает дальнейшую перегрузку в классах-потомках виртуальных и абстрактных методов, объявленных в одном из классов-предков данного класса.

Метод с модификатором partial может содержать одно отдельное определяющее объявление (не имеющее тела) и одну реализацию. Если реализация не будет найдена, такой метод будет исключен из компиляции. Обычно такие методы применяются в разделяемых классах, когда тело метода описано в одной части класса, а реализация – в другой.

Поле с модификатором readonly доступно только для чтения. Модификатор volatile говорит компилятору, что содержимое поля может изменяться несколькими потоками, поэтому не нужно пытаться оптимизировать доступ к нему.

Для членов структур запрещены модификаторы abstract, protected, sealed, virtual.

Некоторые имена и сигнатуры резервируются компилятором языка C#

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

1)Имена, совпадающие по написанию с ключевыми словами языка (если они не предваряются символом «@», см. п. 3.1.6.1);

2)Имя класса. Только имя конструктора и деструктора может совпадать с именем класса (см. п. 4.4.2, 4.4.3);

3)Для свойства P типа T зарезервированы сигнатуры «T get_P()» и «void set_P(T value)» (см. п. 4.5.1);

4)Для индексатора типа T со списком формальных параметров L заре-

зервированы сигнатуры «T get_Item(L)» и «void set_Item(L, T value)» (см. п. 4.5.2);

5)Для события E типа делегата T зарезервированы сигнатуры «void add_E(T handler)» и «void remove_E(T handler)» (см. § 4.8);

6)Для класса, содержащего деструктор, зарезервирована сигнатура

«void Finalize()» (см. п. 4.4.3).

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

class Program

{

int if; // Ошибка int @if; // ОК

int Program; // Ошибка

259

int get_A; int set_A;

int A { get; set; } // Ошибка

void get_B(int i) { }

void set_B(int i, int j) { } int B { get; set; } // ОК

~Program() { }

int Finalize; // Ошибка

}

Пример: Samples\4.2\4_2_2_members.

4.2.3. Статические члены и члены экземпляров

Отдельно остановимся на статических классах и членах класса. Мы можем определить член класса как статический (static member) или член эк-

земпляра (instance member).

По умолчанию каждый член определен как член экземпляра. Это значит, что для каждого экземпляра класса делается своя копия этого члена. Для члена экземпляра определен идентификатор this, являющийся ссылкой на экземпляр, для которого в настоящий момент используется данный член. Например:

class MyTest

{

private int x;

public void F1(int x)

{

this.x = x;

}

public static void F2(int x)

{

this.x = x; // Ошибка

}

}

В этом примере в записи «this.x = x» this.x – это обращение к члену класса, а x – к аргументу метода. Статические члены определены для класса, а не для экземпляра класса, поэтому для них данный идентификатор не определен.

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

260