Опубликован: 25.03.2010 | Доступ: свободный | Студентов: 1447 / 158 | Оценка: 4.31 / 4.00 | Длительность: 25:42:00
Лекция 20:

Консольные приложения в С#

< Лекция 19 || Лекция 20: 1234567891011

Создание объектов и их инициализация

Все объекты в C# создаются на куче и с помощью оператора new. Инициализация объектов при их создании выполняется функциями-членами класса, которые называются конструкторами. Конструкторы не нужно вызывать специально. Они вызываются автоматически при создании объекта и только один раз. Повторно вызвать конструктор как метод для уже существующего объекта невозможно.

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

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

Имена конструкторов должны совпадать с именем класса. Конструкторы должны иметь модификатор доступа public.

Для иллюстрации сказанного продолжим модификацию нашего проекта консольного приложения ConsoleApplication1 в части объявления класса HelloClass.

  • Модифицируйте класс следующим образом
using System;
  
namespace ConsoleApp
{
class HelloClass
{
// Внутренние переменные
private int x, y;
  
// Конструкторы
public HelloClass() // Конструктор по умолчанию
{
Console.WriteLine("Конструктор по умолчанию");
}
  
public HelloClass(int a, int b) // Конструктор с параметрами
{
Console.WriteLine("Конструктор с параметрами");
x = a;
y = b;
}
  
// Сервисы класса
public int GetX(){return x;}
public int GetY(){return y;}
  
// Точка входа в программу
static void Main(string[] args)
  {
  // Создаем два объекта-экземпляра класса
  HelloClass ob1 = new HelloClass(); // Вызов конструктора по умолчанию
  Console.WriteLine("ob1: x = {0}; 
    y = {1} \n", ob1.GetX(), ob1.GetY());
  
  HelloClass ob2 = new HelloClass(10, 15); // Вызов общего конструктора
  Console.WriteLine("ob2: x = {0};
     y = {1}", ob2.GetX(), ob2.GetY());
  while(true);
  }
}
}
Листинг 20.6 . Введение конструкторов в класс HelloClass
  • Постройте и запустите проект через кнопку Start оболочки, получим результат

Результат применения конструкторов

Конструктор по умолчанию 
ob1: x = 0; y = 0  
  
Конструктор с параметрами 
ob2: x = 10; y = 15

Мы видим, что переменные x и y в первом объекте не остались брошенными, как это бы было в C++, а инициализировались нулями в соответствии с их типом.

Деструкторы в C# применять не нужно, поэтому они не предусмотрены синтаксисом и в C# даже нет зарезервированного слова delete. Программист не должен заботиться об освобождении затребованной у системы памяти на куче. Об этом позаботится специальный механизм, который называется сборщиком мусора ( GC - Garbare Collector ). Сборщик мусора платформы . NET освободит память автоматически.

Вынесение точки входа в самостоятельный класс

В последнем примере мы внутри класса HelloClass в методе Main() создавали объекты того же самого класса. Это вносит лишнюю путаницу в изучение кода. Функция Main() никакого отношения к классу HelloClass не имеет и присутствует там только из-за того, что глобальные функции в C# недопустимы и ее нужно куда-то приткнуть. Так давайте же вынесем ее в отдельный класс, чтобы отделить "котлеты от мух".

  • Измените код файла HelloClass.cs так, как показано ниже
using System;
  
namespace ConsoleApp
{
class HelloClass
{
// Внутренние переменные
private int x, y;
  
// Конструкторы
  public HelloClass() // Конструктор по умолчанию
  {
  Console.WriteLine("Конструктор по умолчанию");
  }
  
  public HelloClass(int a, int b) // Конструктор с параметрами
  {
  Console.WriteLine("Конструктор с параметрами");
  x = a;
  y = b;
  }
  
  // Сервисы класса
  public int GetX(){return x;}
  public int GetY(){return y;}
}
  
  
//**************************************************************  
class HelloApp
{
// Точка входа в программу
static void Main(string[] args)
{
// Создаем два объекта-экземпляра класса
HelloClass ob1 = new HelloClass(); // Вызов конструктора по умолчанию
Console.WriteLine("ob1: x = {0}; 
  y = {1} \n", ob1.GetX(), ob1.GetY());
  
HelloClass ob2 = new HelloClass(10, 15); // Вызов общего конструктора
Console.WriteLine("ob2: x = {0}; 
  y = {1}", ob2.GetX(), ob2.GetY());
while(true);
}
}
}
Листинг 20.7 . Выделение точки входа в отдельный класс

Здесь мы ничего кардинального на сделали, просто объявили новый класс и в его тело вынесли функцию Main().

  • Запустите приложение и получите тот же самый результат

Тот же результат после вынесения точки входа в самостоятельный класс

Конструктор по умолчанию 
ob1: x = 0; y = 0  
  
Конструктор с параметрами 
ob2: x = 10; y = 15
  • Поменяйте местами порядок следования классов и опять постройте приложение. Ничего не изменилось. Но в C++ пришлось бы в этом случае применять упреждающее объявление класса HelloClass перед классом HelloApp, поскольку его однопроходный компилятор встретив использование класса HelloClass еще не дошел бы до объявления самого класса HelloClass.

Вынесение класса с точкой входа в отдельный файл

Мы в данном примере нехорошо поступили (ну, почти нехорошо), потому что принято каждый класс размещать в отдельном файле с названием, обычно совпадающем с именем класса. Исправим это.

  • Выполните команду Add Class в меню Project оболочки

  • Заполните окно мастера так

  • После нажатия кнопки Open мастер создаст новый файл с именем HelloApp.cs. Перенесите класс HelloApp из файла HelloClass в новый файл, при этом не забудьте изменить пространство имен на прежнее ConsoleApp. Не забудьте удалить код перенесенного класса HelloApp в прежнем файле HelloClass.cs. Окончательно новый файл должен выглядеть так
using System;
  
namespace ConsoleApp
{
class HelloApp
  {
  // Точка входа в программу
  static void Main(string[] args)
  {
  // Создаем два объекта-экземпляра класса
  HelloClass ob1 = new HelloClass(); // Вызов конструктора по умолчанию
  Console.WriteLine("ob1: x = {0}; 
    y = {1} \n", ob1.GetX(), ob1.GetY());
  
  HelloClass ob2 = new HelloClass(10, 15); // Вызов общего конструктора
  Console.WriteLine("ob2: x = {0}; 
    y = {1}", ob2.GetX(), ob2.GetY());
  while(true);
  }
  }
}
Листинг 20.8 . Перенос класса с функцией Main() в отдельный файл HelloApp.cs
  • Постройте приложение и убедитесь, что выходные результаты остались прежними

Тот же результат после переноса класса с функцией Main() в отдельный файл

Конструктор по умолчанию 
ob1: x = 0; y = 0  
  
Конструктор с параметрами 
ob2: x = 10; y = 15

Инициализация членов без конструктора

В C++ в классе можно простые переменные только объявлять, а инициализировать их нужно в конструкторе или устанавливать путем присваивания функциями Set() из клиента. В C# такое ограничение отсутствует и данные-члены класса можно инициализировать при их объявлении в классе. Примеры

class Text
{
private int MyInt = 90;
private string MyString = "My initial value";
private HotRod viper = new HotRod(200, "Chucky", Color.Red);
.............................................................
}
  • Измените код класса HelloClass нашего примера так, как показано ниже
using System;
  
namespace ConsoleApp
{
  class HelloClass
  {
    // Внутренние переменные
    private int x = 100, y = 150;
  
    // Конструкторы
    public HelloClass() // Конструктор по умолчанию
    {
      Console.WriteLine("Конструктор по умолчанию");
    }
  
    public HelloClass(int a, int b) // Конструктор с параметрами
    {
      Console.WriteLine("Конструктор с параметрами");
      x = a;
      y = b;
    }
  
    // Сервисы класса
    public int GetX(){return x;}
    public int GetY(){return y;}
  }
}
Листинг 20.9 . Инициализация данных без конструктора
  • После построения проекта получим результат

Результат после прямой инициализации данных

Конструктор по умолчанию 
ob1: x = 100; y = 150  
  
Конструктор с параметрами 
ob2: x = 10; y = 15

Важное замечание

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

< Лекция 19 || Лекция 20: 1234567891011
Максим Филатов
Максим Филатов

Прошел курс. Получил код Dreamspark. Ввожу код на сайте, пишет:

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

 

Как активировать код?