CSBasicCourse2ndedPodbelsky / CSBasicCourse2ndedPodbelsky
.pdf=выражение
=инициализатор_массива
=new тип (аргументы_конструктора)
Ввыражение инициализатора, в инициализатор массива и в выражения,
используемые в качестве аргументов конструктора, могут входить константы–
литералы, а также другие статические члены этого класса.
Нестатические члены невозможно использовать в инициализирующем
выражении статического поля.
Пример инициализации и использования статических полей:
// 10_01.cs - статические поля класса using System;
class T {
int x; // поле объектов класса
static int y = 3; // y = x + 5; - ошибка: х – поле объекта public static int z = 5 - y; // эквивалент: z = 5 - T.y;
}
class Program
{
static void Main()
{
// Console.WriteLine("T.y = " + T.y); // Error! T.y is private! int z = T.z; // z и T.z - разные переменные! Console.WriteLine("T.z = " + ++T.z); // изменяется T.z Console.WriteLine("z = {0}", z);
}
}
Результат выполнения программы:
T.z = 3 z = 2
Следует отметить одну особенность инициализации статических полей
"поле:инициализация статических полей" . Вначе они все получают умалчиваемые значения (для арифметических типов – нулевые). Затем последовательно (сверху вниз) выполняются инициализаторы. Тем самым, если в инициализирующее выражение входит в качестве операнда статическое поле, которое ещё не инициализировано явно, то для него берётся умалчиваемое (например, нулевое)
значение. В качестве примера рассмотрим программу:
// 10_02.cs - статические поля - порядок инициализации using System;
class T
{
public static int x = y; static int y = 3; public static int z = y;
}
class Program
{
static void Main()
{
Console.WriteLine("T.x = " + T.x);
Console.WriteLine("T.z = " + T.z);
}
}
Результат выполнения программы:
T.x = 0
T.z = 3
Обратите внимание, что поле y по умолчанию закрытое (имеет статус доступа private) и обращение к нему невозможно вне класса T.
Открытые статические члены разных классов одной программы могут использоваться в одном выражении. В следующей программе объявлены три класса со статическими полями, обращения к которым используются в инициализирующих
выражениях разных классов.
// 10_03.cs - статические поля разных классов using System;
class c1 {
public static double orbit = 2 * c2.pi * c3.radius;
}
class c2 {
public static double pi = double.Parse(c3.str);
}
class c3 {
public static string str = "3,14159"; public static double radius = 10;
}
class Program
{
static void Main()
{
Console.WriteLine("c1.orbit = {0}", c1.orbit); c3.radius = 20;
Console.WriteLine("c3.radius = {0}", c3.radius); Console.WriteLine("c1.orbit = {0}", c1.orbit);
}
}
Результат выполнения программы: c1.orbit = 62,8318
c3.radius = 20 c1.orbit = 62,8318
Инициализация статических полей "поле:инициализация статических полей"
выполняется только однажды. Поэтому значение поля c1.orbit не изменилось после изменения c3.radius в методе Main( ).
10.3. Статические константы
Константы "константы" могут быть локализованы в теле метода, а могут принадлежать классу. В последнем случае они по умолчанию без модификатора static являются статическими, т.е. недоступны через ссылку на объекты класса.
Объявление статической константы "константы:объявление статической
константы" имеет вид:
модификаторыopt const тип_константы список_объявлений_констант
Необязательные модификаторы для констант – это при отсутствии
наследования модификаторы доступа (public, private, protected, internal).
Объявление из списка_объявлений_констант имеет вид:
идентификатор=инициализирующее_выражение.
Идентификатор служит именем статической константы. В
инициализирующее выражение имеют право входить только константы–литералы и статические константы. (Порядок их размещения в объявлении класса безразличен.) Каждая константа должна быть обязательно явно инициализирована.
Умалчиваемые значения для статических констант не предусмотрены. Пример с классом статических констант:
// 10_04.cs - статические константы класса using System;
class Constants
{
public const double скорость_света = 299793; // км/сек public const double радиус_электрона = 2.82e-13; // см
}
class Program
{
static void Main()
{
Console.WriteLine("радиус_электрона = {0}", Constants.радиус_электрона); }
}
Результат выполнения программы:
радиус_электрона = 2,82E-13
В отличие от статических полей константы инициализируются однажды и не принимают до явной инициализации промежуточных умалчиваемых значений.
Поэтому последовательность размещения объявлений статических констант не
важна. Для иллюстрации этой особенности приведём следующую программу:
// 10_05.cs - статические константы разных классов using System;
class One {
public const double circle = 2 * pi * Two.radius; public const double pi = 3.14159;
}
class Two
{
public const double radius = 20;
}
class Program
{
static void Main()
{
Console.WriteLine("One.circle = {0}", One.circle);
}
}
Результат выполнения программы:
One.circle = 125,6636
Следует обратить внимание на отличия статических констант от статических полей с модификатором readonly (только чтение). Статические константы получают значения при компиляции, а статические поля (даже снабженные модификатором readonly) инициализируются в процессе выполнения программы.
Инициализация статических полей выполняется в порядке их размещения в тексте объявления класса, и до инициализации поле имеет умалчиваемое значение. В то же время инициализирующие выражения статических констант вычисляются в
"рациональной" последовательности, независимо от порядка размещения
объявлений. Эти особенности иллюстрируют объявления констант в классе One: public const double circle = 2*pi*Two.radius;
public const double pi=3.14159;
В инициализатор константы circle входит константа pi, объявление которой
следует за объявлением circle. Несмотря на это, значением circle |
будет 125,6636. |
|
Конечно, при инициализации нескольких констант недопустимо появление |
||
"зацикливания". В инициализатор константы K1 не должна входить константа K2, в |
||
инициализатор которой входит константа K1. |
|
|
Указанное "зацикливание" никогда не возникает при инициализации |
||
статических полей (даже имеющих модификатор |
readonly). Поле F2, объявление |
|
которого размещено ниже, может входить в инициализатор поля F1 – оно имеет |
||
там умалчиваемое значение. При этом поле F1, использованное в инициализатор F2, |
||
будет иметь там уже конкретное значение. Замена |
const на |
static readonly в |
предыдущем примере: |
|
|
public static readonly double circle = 2*pi*Two.radius; public static readonly double pi=3.14159;
При такой инициализации значение circle будет 0.
10.4. Статические методы
Статический метод "метод:статический метод" Main() мы уже используем,
начиная с первой программы этой книги. Нам уже известно, что в теле метода
Main() можно обращаться ко всем статическим членам того класса, где размещён метод Main( ).
Статические методы, отличные от Main( ), мы уже подробно рассматривали, но ограничивались их размещением в том классе, где находится метод Main(). В этом случае для обращения к методу можно использовать выражение имя_метода(список_аргументов). Если статический метод определён в другом классе, то для обращения к нему используется выражение вида:
имя_класса.имя_метода(список_аргументов)
По умолчанию статический метод имеет модификатор доступа private, т.е
метод доступен только внутри класса. В объявлении статического метода, который планируется вызывать вне класса, необходимо указать модификатор доступа. В
зависимости от дальнейшего применения метода используются модификаторы public (открытый), protected – (защищещённый), internal – (внутренний), protected internal – (защищённый внутренний). Области видимости, которые обеспечены перечисленными модификаторами, те же что и для полей классов.
Статические методы применяются: для инициализации статических полей; для обращения к статическим полям с целью их изменения или получения значений; для обработки внешних данных, передаваемых методу через аппарат параметров; для вызова из других методов класса. Особо нужно отметить, что в теле статического метода недоступны нестатические члены того класса, которому принадлежит метод.
В следующей программе статические методы используются для инициализации
статических полей и для обеспечения внешнего доступа к закрытому полю класса.
// 10_06.cs - статические методы класса using System;
class newClass { static int n = 5; static int x = f1(n);
public static int y = fb(n) ? 10 : -10;
public static int getX() { return x; }
static bool fb(int a) { return a % 2 == 0 ? true : false; } static int f1(int d) { return d * d * d; }
}
class Program
{
static void Main()
{
Console.WriteLine("newClass.y = " + newClass.y); Console.WriteLine("newClass.getX() = " + newClass.getX());
}
}
Результат выполнения программы: newClass.y = -10
newClass.getX() = 125
Обратите внимание, что в классе newClass только два открытых члена – поле int y и метод getX(). Поля x, n и методы fb(), f1() недоступны вне класса.
В теле любого метода могут быть объявлены локальные переменные
"переменные:локальные переменные" и константы с типами ссылок и значений.
Имена таких переменных имеют право совпадать с именами статических членов того класса, в котором размещён метод. В этом случае локальная переменная
"экранирует" одноимённую статическую переменную, то есть имя без квалификатора "имя_класса." при совпадении имён относится только к локальному объекту метода. В качестве примера рассмотрим следующий метод Main() из
класса Test_cs:
// 10_07.cs - Статические поля класса и локальные данные методов
using System; |
|
class Test_cs { |
// инициализация разрешена |
static int n = 10; |
|
static string line = new string('*', n); |
|
static double constant = 9.81; // поле класса Test_cs |
|
double pi = 3.14159; // поле объекта класса Test_cs |
|
static void Main( ) |
{ |
const double PI = 3.14159; // локальная константа double circle; // локальная переменная
//circle = 2 * pi * n; // ошибка - нет объекта класса Test_cs circle = 2 * PI * n;
Console.WriteLine("Длина окружности=" + circle.ToString( )); Console.WriteLine(line);
Test_cs.n = 20; // изменили значение поля класса line = new string('*', n); // изменили значение ссылки Console.WriteLine(line);
const double constant = 2.718282; // локальная константа Console.WriteLine("Test_cs.constant=" + Test_cs.constant); Console.WriteLine("constant=" + constant);
}
}
Результат выполнения программы:
Длина окружности=62,8318
**********
********************
Test_cs.constant=9,81 constant=2,718282
В тексте метода Main( ):
PI – локальная именованная константа; circle – локальная переменная;
n, Test_cs.n – два обращения к одному и тому же статическому полю класса; line – статическая ссылка–поле класса;
constant – локальная константа, имя которой совпадает с именем статического поля класса Test_cs.
Попытка обращения в теле метода Main( ) к нестатическому полю pi приводит к ошибке – пока не создан объект класса (объект, которому будет принадлежать поле pi) к его нестатическим полям обращаться нельзя, их нет.
Каждое статическое поле существует только в единственном экземпляре.
Статические поля класса играют роль глобальных переменных для всех методов, у
которых есть право доступа к этому классу.
Итак, пока не создан объект класса, существуют и доступны только статические члены класса.
10.5. Статический конструктор
Назначение статического конструктора - инициализация статических полей класса. Статический конструктор "конструктор:статический конструктор"
вызывается средой исполнения приложений (CLR) перед первым обращением к любому статическому полю класса или перед первым созданием экземпляра класса.
Конструкторы классов "конструктор:конструкторы классов" – статические и
нестатические (последние рассмотрены в главе 11) обладают рядом особенностей,
отличающих их от других методов классов. Имя конструктора всегда совпадает с именем того класса, которому он принадлежит. Для конструктора не указывается тип возвращаемого значения (даже тип void для конструктора запрещён). В теле
конструктора нет необходимости, но допустимо, использовать оператор return.
Для статического конструктора нельзя использовать модификаторы доступа.
Класс может иметь только один статический конструктор. Для статического
конструктора параметры не указываются – спецификация параметров должна быть пустой.
Формат объявления статического конструктора "конструктор:объявление
статического конструктора" : static имя_класса( )
{операторы_тела_конструктора}
Статический конструктор невозможно вызвать непосредственно из программы
– статический конструктор вызывается только автоматически. Следует обратить внимание, что статический конструктор вызывается после выполнения инициализаторов статических полей класса. Основное назначение статического конструктора – выполнять более сложные действия, нежели инициализаторы полей и констант. Для статического конструктора недоступны нестатические члены класса.
В качестве примера определим статический конструктор того класса, в
котором размещён метод Main( ). В том же классе определим несколько статических полей и выполним их инициализацию как с помощью
инициализаторов, так и с применением статического конструктора.
// 10_08.cs - Инициализаторы и статический конструктор using System;
class Program
{
static int[] ar = new int[] { 10, 20, 30, 40 }; static int numb = n + ar[3] - ar[1];
// Статический конструктор: static Program ()
{ numb /= n; n = ar[1] + n; } static int n = 2;
static void Main()
{
Console.WriteLine("numb={0}, n = {1}", numb, n);
}
}
Результат выполнения программы: numb=10, n = 22
В классе определены статические поля: ссылка ar, связанная с целочисленным массивом из 4-х элементов; целочисленные переменные numb и n. В теле статического конструктора переменным numb и n присваиваются значения,
отличные от тех, которые они получили при инициализации. Текст программы и результаты её выполнения иллюстрируют следующие правила, большинство из которых мы уже приводили.
Инициализация статических полей "поле:инициализация статических полей"
выполняется последовательно (сверху - вниз) по тексту определения класса. Поля,
для которых инициализация ещё не выполнена, имеют умалчиваемые значения. (Для арифметических типов умалчиваемое значение статического поля равно нулю.) В инициализирующих выражениях статических полей допустимо использовать обращения к другим статическим членам классов. После выполнения инициализации статических полей выполняется статический конструктор, действия которого могут изменить значения статических полей.
10.6. Статические классы
Как рекомендует Стандарт C# [2], классы, которые не предназначены для создания объектов и которые содержат только статические члены, нужно