
- •Создание консольного проекта про c#
- •Выполнение проекта по умолчанию после "большого взрыва"
- •Проект WindowsHello
- •Структура класса c#
- •Создание объектов и их инициализация
- •Вынесение класса с точкой входа в отдельный файл
- •Инициализация членов без конструктора
- •Типы данных в c#
- •Общие сравнения структурных и ссылочных типов
- •Базовый тип System.Object
- •Перегрузка стандартных методов класса System.Object
- •Перегрузка (замещение) виртуального метода ToString()
- •Статические методы класса System.Object
- •Системные типы данных и их псевдонимы как встроенные типы c#
Вынесение класса с точкой входа в отдельный файл
Мы в данном примере нехорошо поступили (ну, почти нехорошо), потому что принято каждый класс размещать в отдельном файле с названием, обычно совпадающем с именем класса. Исправим это.
Выполните команду 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);
}
}
}
Листинг 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;}
}
}
Листинг 9 . Инициализация данных без конструктора
После построения проекта получим результат
Результат после прямой инициализации данных
Конструктор по умолчанию
ob1: x = 100; y = 150
Конструктор с параметрами
ob2: x = 10; y = 15
Важное замечание
Отметим, что подобная прямая инициализация членов-данных в структурах недопустима. Перегрузка конструктора по умолчанию в структурах тоже недопустима.
Типы данных в c#
В C# различают структурные типы ( reference-based ) и ссылочные ( value-based ). Переменная структурного типа представляет закрепленное за ней само значение оперативной памяти. Переменная ссылочного типа содержит лишь адрес области оперативной памяти с размещаемым в этой области значением. Все структурные переменные размещаются на стеке, а ссылочные - на управляемой куче ( managed heap ). К структурным типам относятся перечисления и структуры, а к ссылочным - классы, массивы, указатели, интерфейсы.
Когда выполняется присваивание одной структурной переменной другой, то создается побитовая копия данных, которые размещены в разных областях стековой памяти и существуют независимо друг от друга. При выполнении присваивания ссылочных переменных создается копия адреса, после чего обе переменные будут ссылаться на одну и ту же область памяти на управляемой куче. То есть создается как-бы псевдонимы одной и той же области памяти. Это означает, что изменения объекта по одной ссылочной переменной равноценно изменениям по псевдониму
Создайте консольное приложение C# или модифицируйте уже созданное. Заполните файл с точкой входа следующим кодом
using System;
namespace Test
{
struct FOO
{
public int x, y;
}
class ValRefClass
{
static void Main(string[] args)
{
// Создаем объект на стеке
// При создании структуры с конструктором по умолчанию
// ключевое слово new является необязательным,
// а можно просто FOO f1;
FOO f1 = new FOO();
f1.x = 100;
f1.y = 100;
// Создается объект на стеке без ключевого слова new
// и осуществляется побитовое копирование в другую память
FOO f2 = f1;
// Вывод до изменения
Console.WriteLine("Содержимое объектов
f1 и f2 до изменения");
Console.WriteLine("Объект f1: x={0};
y={1}", f1.x, f1.y);
Console.WriteLine("Объект f2: x={0};
y={1}", f2.x, f2.y);
// Внесение изменений
f1.x = 1; f1.y = 2; f2.x = 3; f2.y = 4;
// Вывод после изменения
Console.WriteLine("\nСодержимое объектов
f1 и f2 после изменения");
Console.WriteLine("Объект f1: x={0};
y={1}", f1.x, f1.y);
Console.WriteLine("Объект f2: x={0};
y={1}", f2.x, f2.y);
while(true);
}
}
}
Листинг 10 . Код для переменных структурного типа
Результаты экрана
Содержимое объектов f1 и f2 до изменения
Объект f1: x=100; y=100
Объект f2: x=100; y=100
Содержимое объектов f1 и f2 после изменения
Объект f1: x=1; y=2
Объект f2: x=3; y=4
Измените в исходном коде для типа FOO ключевое слово struct на class, тем самым сразу получим ссылочный тип. Запустите программу - получится результат
using System;
namespace Test
{
class FOO
{
public int x, y;
}
class ValRefClass
{
static void Main(string[] args)
{
// Создаем объект на куче
// Теперь слово new является обязательным, а также
// обазательны круглые скобки конструктора по умолчанию
FOO f1 = new FOO();
f1.x = 100;
f1.y = 100;
// Создается не объект, а ссылку, и после копирования
// адреса получаем псевдоним на ту же область памяти
FOO f2 = f1;
// Вывод до изменения
Console.WriteLine("Содержимое объектов f1 и
f2 до изменения");
Console.WriteLine("Объект f1: x={0};
y={1}", f1.x, f1.y);
Console.WriteLine("Объект f2: x={0};
y={1}", f2.x, f2.y);
// Внесение изменений
f1.x = 1; f1.y = 2; f2.x = 3; f2.y = 4;
// Вывод после изменения
Console.WriteLine("\nСодержимое объектов f1 и
f2 после изменения");
Console.WriteLine("Объект f1: x={0};
y={1}", f1.x, f1.y);
Console.WriteLine("Объект f2: x={0};
y={1}", f2.x, f2.y);
while(true);
}
}
}
Листинг 11 . Код для переменных ссылочного типа
Результаты экрана
Содержимое объектов f1 и f2 до изменения
Объект f1: x=100; y=100
Объект f2: x=100; y=100
Содержимое объектов f1 и f2 после изменения
Объект f1: x=3; y=4
Объект f2: x=3; y=4
Здесь мы видим, что в обоих случаях мы изменяли один и тот же объект, который и сохранил последние значения. Теперь f1 и f2 - не более чем ссылки на один и тот же диапазон памяти в области управляемой кучи.
Для того, чтобы объекты, адресуемые переменными f1 и f2, занимали разные области памяти, нужно запросить память у операционной системы для каждого из них и сохранить возвращенные адреса в этих переменных.
Следующий код и полученный результат иллюстрируют сказанное
using System;
namespace Test
{
class FOO
{
public int x, y;
}
class ValRefClass
{
static void Main(string[] args)
{
// Создаем первый объект на куче
FOO f1 = new FOO();
f1.x = 100;
f1.y = 100;
// Создается второй объект на куче
FOO f2 = new FOO();
f2.x = 100;
f2.y = 100;
// Вывод до изменения
Console.WriteLine("Содержимое объектов f1 и
f2 до изменения");
Console.WriteLine("Объект f1: x={0};
y={1}", f1.x, f1.y);
Console.WriteLine("Объект f2: x={0};
y={1}", f2.x, f2.y);
// Внесение изменений
f1.x = 1; f1.y = 2; f2.x = 3; f2.y = 4;
// Вывод после изменения
Console.WriteLine("\nСодержимое объектов
f1 и f2 после изменения");
Console.WriteLine("Объект f1: x={0};
y={1}", f1.x, f1.y);
Console.WriteLine("Объект f2: x={0};
y={1}", f2.x, f2.y);
while(true);
}
}
}
Листинг 12 . Код для переменных ссылочного типа
Результаты экрана
Содержимое объектов f1 и f2 до изменения
Объект f1: x=100; y=100
Объект f2: x=100; y=100
Содержимое объектов f1 и f2 после изменения
Объект f1: x=1; y=2
Объект f2: x=3; y=4