Файл: 1_C#_Введение_в_программирование_Уч_пособ_(Марченко-2005).pdf
ВУЗ: Не указан
Категория: Не указан
Дисциплина: Не указана
Добавлен: 11.12.2025
Просмотров: 1356
Скачиваний: 3
И ещё один пример, в котором строится массив myArray, элементами которого являются массивы. Каждый из составляющих имеет собственные размеры.
//cs_array_of_arrays.cs using System;
public class ArrayTest
{
public static void Main()
{
//Declare the array of two elements: int[][] myArray = new int[2][];
//Initialize the elements: myArray[0] = new int[5] {1,3,5,7,9}; myArray[1] = new int[4] {2,4,6,8};
//Display the array elements:
for (int i=0; i < myArray.Length; i++)
{
Console.Write(“Element({0}):”, i);
for (int j = 0 ; j < myArray[i].Length ; j++)
Console.Write(“{0}{1}”, myArray[i][j], j == (myArray[i].Length-1) ? “” : “ ”); Console.WriteLine();
}
}
}
Результат:
Element(0): 1 3 5 7 9
Element(1): 2 4 6 8
Массивы как параметры
В качестве параметра методу всегда можно передать ссылку на ОДНОМЕРНЫЙ массив. Массив, первая спецификация размерности которого в объявлении имеет вид …[] …
Тип и количество составляющих данный массив компонентов для механизма передачи параметров значения не имеют. Важно, что в стеке будет выделено определённое (соответствующее значению первой размерности) количество проинициализированных ссылок на составляющие данный одномерный массив элементов.
Этот принцип действует во всех случаях. В том числе и при вызове приложения из командной строки.
Вызов приложения из командной строки с передачей ему в качестве параметров массива ОДНОТИПНЫХ (строковых) значений.
using System; class C1
{
static void Main(string[] args)
{
Console.WriteLine(“Values of parameters:”); for (int i = 0; I < args.Length; i++)
{
Console.WriteLine(“{0}: {1}”, i, args[i]);
}
}
}
Сначала создаётся консольное приложение (пусть под именем ComLine, в файле
ComLine.cs).
Транслятор можно запустить из командной строки, выглядит это примерно так:
C:> csc /t:exe ConLine.cs
47
Результат деятельности транслятора размещается в .exe файле под именем ConLine.exe и также может быть запущен из командной строки с передачей строк символов в качестве входных параметров.
C:>ConLine qwerty asdfgh zxcvbn ok ok ok-k
В окне консольного приложения отобразится следующее множество строк:
Values of parameters:
0:qwerty
1:asdfgh
2:zxcvbn
3:ok
4:ok
5:ok-k
А теперь с использованием оператора foreach:
using System; class C1
{
static void Main(string[] args)
{
Console.WriteLine(“Values of parameters, using foreach:”); foreach (string arg in args)
{
Console.WriteLine(“{0}”, arg);
}
}
}
Запускаем:
C:>ConLine qwerty asdfgh zxcvbn ok ok ok-k
Получаем:
Values of parameters, using foreach: qwerty
asdfgh zxcvbn ok
ok ok-k
Полностью построенный массив можно передать в качестве входного параметра методу.
Пустая ссылка на массив может быть передана методу в качестве выходного параметра.
Например:
int[] myArray; // myArray == null PrintArray(myArray);
Можно также совместить передачу массива как параметра методу с предварительной инициализацией этого массива. Например:
PrintArray(new int[] {1, 3, 5, 7, 9});
In the following example, a string array is initialized and passed as a parameter to the PrintArray method, where its elements are displayed:
// cs_sd_arrays.cs using System;
public class ArrayClass
{
static void PrintArray(string[] w)
{
for (int i = 0 ; i < w.Length ; i++)
{
48
Console.Write(w[i] + “{0}”, i < w.Length - 1 ? “ ” : “”);
}
Console.WriteLine();
}
public static void Main()
{
//Declare and initialize an array: string[] WeekDays = new string []
{”Sun”,”Sat”,”Mon”,”Tue”,”Wed”,”Thu”,”Fri”};
//Pass the array as a parameter: PrintArray(WeekDays);
}
}
Вывод:
Sun Sat Mon Tue Wed Thu Fri
Спецификатор params
Неопределённое (переменное) количество (ОДНОТИПНЫХ!) параметров или список параметров переменной длины.
Это всегда последний параметр в списке параметров со спецификатором params. В выражении вызова метода должен располагаться либо список однотипных параметров (этот список преобразуется в массив значений), либо ссылка на
ОДНОМЕРНЫЙ массив значений определённого типа.
using System;
class Class1
{
static void Main(string[] args)
{
f1(0,1,2,3,4,5);
f1(0,1,2,3,4,5,6,7,8,9,10);
f2(new int[,]{{0,1},{2,3}}, new int[,]{{0,1,2,3,4,5},{6,7,8,9,10,11}}); f2(new int [,]{{0,1},{2,3}});
}
static void f1(params int[] m)
{
Console.WriteLine(m.Length.ToString());
}
static void f2(params int[][,] p)
{
Console.WriteLine(p.Length.ToString());
}
}
Main в классе. Точка входа
Без статической функции (метода) Main невозможно построить выполняемую программу. Без явно обозначенной точки входа сборка не можен выполняться.
В сборке можно располагать несколько классов. Каждый класс располагает собственным набором методов. В каждом классе могут располагаться одноименные методы. В следующем примере объявляются три класса в одном пространстве имён. В каждом классе объявляется независимая точка входа. Три (!) СТАТИЧЕСКИЕ функции Main. Возможно и такое. При этом главная проблема - при компиляции надо явным образом указать точку входа.
Это можно сделать из командной строки при вызове компилятора. Например, так: c:\ csc /main:Class1.Class3 Example1.cs
49
Можно через диалог The Startup Object property среды разработки приложений (меню Проект-Свойства проекта, далее - General, Common Properties, <Projectname> Property Pages Dialog Box (Visual C#)), который обеспечивает спецификацию значений, которые явным образом НЕ ПРОПИСАНЫ в проекте. В разделе Startup object, надо раскрыть список классов и указать соответствующий класс.
Транслятор соберёт сборку, В которой будет обеспечена передача управления соответствующей функции Main (одной из трёх!).
using System; namespace Example1
{
//=============================================== public class Class1
{
// Спецификатор public нужен здесь. Третий класс. public class Class3
{
public static void Main()
{
string[] sss = new string[]{Class1.s.ToString(),”12345”}; Class1.Main(sss);
}
}
int d = 0;
public static int s;
static void Main(string[] args)
{
Class1 c1 = new Class1(); f1(c1);
c1.f2();
Class2 c2 = new Class2(); //c2.f2();
c2.f3();
string[] sss = new string[] {”qwerty”, c1.ToString()}; Class2.Main(sss);
}
static void f1(Class1 x)
{
//x.s = 100; s = 0;
Class1.s = 125; x.d = 1;
//d = 100;
}
void f2()
{
s = 0; Class1.s = 100; //this.s = 5;
//Class1.d = 125; this.d = 100;
d = 100;
}
}
//=============================================== class Class2
{
int d; static int s;
public static void Main(string[] args)
{
Class1.Class3.Main(); Class2 c2 = new Class2();
50
f1(c2);
c2.f2();
//Class1.Main();
}
static void f1(Class2 x)
{
//x.s = 100; s = 0;
Class2.s = 125; x.d = 1;
//d = 100;
}
void f2()
{
s = 0; Class1.s = 100; //this.s = 5;
//Class1.d = 125; this.d = 100;
d = 100;
}
public void f3()
{
s = 0; Class1.s = 100; //this.s = 5;
//Class1.d = 125; this.d = 100;
d = 100;
}
}
//===============================================
}
Структура также может иметь свою точку входа!
using System;
namespace defConstructors
{
struct MyStruct
{
static void Main(string[] args)
{
Console.WriteLine(“Ha-ha-ha”);
}
}
}
Создание объекта. Конструктор
Конструктором называется группировка кода, которой передаётся управление при создании объекта. Синтаксис объявления конструктора аналогичен обявлению метода. Те же спецификаторы доступа, имя, список параметров. Особенности конструктора заключаются в том, что:
конструктор НЕ ИМЕЕТ НИКАКОГО спецификатора возвращаемого даже void,
имя конструктора полностью совпадает с именем класса или структуры,
в классе и в структуре можно объявлять множество вариантов конструкторов. Они должны отличаться списками параметров. В структуре невозможно объявить конструктор с пустым списком параметров,
не существует выражения вызова для конструктора, управление в конструктор передаётся посредством выполнения специальной операции new.
ВC# ключевое слово new может быть использовано как ОПЕРАЦИЯ или как МОДИФИКАТОР.
new как операция используется:
51
для ссылочных типов (типов-ссылок) при создании объектов в уравляемой памяти и передачи управления конструкторам,
для размерных типов (типов-значений) при создании объектов в СТЕКЕ. Возможно, что при этом может потребоваться обращение к конструктору.
new как модификатор используется для сокрытия наследуемых из базового класса данных и методов. Об этом позже. После того, как рассмотрим подробнее принцип наследования.
Операция new
new операция используется для создания объектов и передачи управления конструкторам, например:
Class1 myVal = new Class1(); // Объект ссылочного типа. Создаётся в куче.
new также используется для обращения к конструкторам типа-значений (размерного типа), например:
int myInt = new int(); // Объект типа int размещается в стеке!
При определении объекта myInt ему было присвоено начальное значение 0, которое является значением по умолчанию для типа int. Следующий оператор имеет тот же самый эффект:
int myInt = 0; // Для размерного типа аналогично.
Конструктор БЕЗ ПАРАМЕТРОВ (конструктор умолчания) обеспечивает инициализацию переменной предопределённым значением. Со списком предопределённых значений, которыми инициализируются объекты предопределённых типов, можно ознакомиться в Default Values Table.
У структуры конструктор умолчания (конструктор без параметров) НЕ ПЕРЕОПРЕДЕЛЯЕТСЯ! Для них объявляются только параметризованные конструкторы.
А вот для предопределённых типов конструкторов с параметрами в принципе нет!
int q = new int();
//int q = new int(125); // Такого нет.
Сколько может иметь конструкторов структура. При использовании правил перегрузки – неограниченное количество.
Сколько может иметь конструкторов класс. Всегда на один больше, чем структура.
В следующем примере, создаются с использованием операции new и конструктора объекты-представители класса и структуры. Для инициализации полей-членов класса используются параметры конструкторов. Присвоение значений осуществляется в теле конструктора с использованием операций присвоения.
//cs_operator_new.cs
//The new operator using System; class NewTest
{
struct MyStruct
{
public int x; public int y;
public MyStruct (int x, int y)
{
this.x = x; this.y = y;
}
}
class MyClass
{
52
public string name; public int id;
public MyClass ()
{
}
public MyClass (int id, string name)
{
this.id = id; this.name = name;
}
}
public static void Main()
{
//Create objects using default constructors: MyStruct Location1 = new MyStruct();
MyClass Employee1 = new MyClass();
//Display values:
Console.WriteLine(“Default values:”);
Console.WriteLine(“ Struct members: {0}, {1}”,
Location1.x, Location1.y);
Console.WriteLine(“ Class members: {0}, {1}”,
Employee1.name, Employee1.id);
//Create objects using parameterized constructors:: MyStruct Location2 = new MyStruct(10, 20);
MyClass Employee2 = new MyClass(1234, “John Martin Smith”);
//Display values:
Console.WriteLine(“Assigned values:”); Console.WriteLine(“ Struct members: {0}, {1}”, Location2.x, Location2.y); Console.WriteLine(“ Class members: {0}, {1}”, Employee2.name, Employee2.id);
}
}
В управляемой памяти нет ничего, что бы создавалось без конструктора
Даже если его присутствие не обозначено явным образом.
string s = “qwerty”;
int[] intArray = {1,2,3,4,5};
Эти операторы являются всего лишь сокращённой формой следующих операторов определения:
string s = new string(new char[]{‘q’,’w’,’e’,’r’,’t’,’y’}); int[] intArray = new int[5]{1,2,3,4,5};
Кто строит конструктор умолчания
Конструктор умолчания (конструктор с пустым списком параметров) строится транслятором по умолчанию. Если класс не содержит явных объявлений конструкторов, именно этот конструктор берёт на себя работу по превращению области памяти в объект.
Class X
{
}
::::::::::
X x = new X(); // Работает конструктор умолчания.
Однако попытка объявления ЛЮБОГО варианта конструктора (с параметрами или без) приводит к тому, что транслятор перестаёт заниматься построением собственных версий конструкторов. Отныне в классе нет больше конструктора умолчания. Теперь всё зависит от соответствия оператора определения объекта
53
построенному нами конструктору. Объявим в производном классе оба варианта конструкторов.
Class X
{
public X(int key){}
}
::::::::::
X x0 = new X(125); // Работает конструктор с параметрами. X x1 = new X(); // Не дело! Конструктора умолчания уже нет!
Однажды взявшись за дело объявления конструкторов, разработчик класса должен брать на себя ответственность за создание ВСЕХ без исключения версий конструкторов. Таковы правила.
Class X
{
public X(int key){} public X(){}
}
::::::::::
X x0 = new X(125); // Работает конструктор с параметрами.
X x1 = new X(); // Работает новый конструктор без параметров.
this в контексте конструктора
Конструктор не вызывается. Передача управления конструктору осуществляется при выполнении операции new.
Ситуация: сложная структура класс. Различные варианты конструкторов, специализирующиеся на создании и инициализации различных вариантов объектов вынуждены выполнять общий список регламентных работ по инициализации объектов.
Оставить ОДИН конструктор, выполняющий ВСЮ “черновую” работу по созданию объектов. “Тонкую” настройку объектов производить после выполнения кода конструктора, непосредственно вызывая соответствующие методы-члены. При этом вызываются методы именно ПОСЛЕ того, как отработает конструктор.
Определить множество специализированных конструкторов, после выполнения которых вызывать дополнительный метод инициализации для общей “доводки” объекта.
Некрасиво. Код получается сложный.
В C# реализован другой подход, который состоит в следующем: Определяется множество разнообразных специализированных конструкторов.
Выделяется наименее специализированный конструктор, которому поручается выполнение обязательной работы.
Обеспечивается передача управления из конструктора конструктору.
Так вот this в контексте конструктора обеспечивает в C# передачу управления от конструктора к конструктору. Таким образом, программист освобождается от необходимости повторного кодирования алгоритмов инициализации для каждого из вариантов конструктора.
Следующий фрагмент программного кода демонстрирует объявление нескольких конструкторов с передачей управления “золушке”.
class Point2D
{
private float x, y;
public Point2D(float xKey, float yKey)
{
Console.WriteLine(“Point2D({0}, {1}) is here!”, xKey, yKey);
//Какой - нибудь сложный обязательный
//код инициализации данных-членов класса.
int i = 0; while (i < 100)
{
x = xKey; y = yKey; i++;
54