Конструкторы в Си-шарп. Указатель this
В этом уроке мы поговорим о таких важных членах класса, как конструкторы.
Конструктор – это метод класса, предназначенный для инициализации объекта при его создании. Инициализация – это задание начальных параметров объектов/переменных при их создании.
Особенностью конструктора, как метода, является то, что его имя всегда совпадает с именем класса, в котором он объявляется. При этом, при объявлении конструктора, не нужно указывать возвращаемый тип, даже ключевое слово void. Конструктор следует объявлять как public, иначе объект нельзя будет создать (хотя иногда в этом также есть смысл).
В классе, в котором не объявлен ни один конструктор, существует неявный конструктор по умолчанию, который вызывается при создании объекта с помощью оператора new.
Объявление конструктора имеет следующую структуру:
public [имя_класса] ([аргументы])
{
// тело конструктора
}
Например, у нас есть класс Автомобиль. Создавая новый автомобиль, значения пробега и количества топлива в баке есть смысл поставить равными нулю:
class Car
{
private double mileage;
private double fuel;
public Car() //объявление конструктора
{
mileage = 0;
fuel = 0;
}
}
class Program
{
static void Main(string[] args)
{
Car newCar = new Car(); // создание объекта и вызов конструктора
}
}
Без конструктора нам бы пришлось после создания объекта отдельно присваивать значения его полям, что очень неудобно.
Конструктор также может иметь параметры.
Пример с тем же автомобилем, только теперь при создании объекта мы можем задать любые начальные значения:
class Car
{
private double mileage;
private double fuel;
public Car(double mileage, double fuel)
{
this.mileage = mileage;
this.fuel = fuel;
}
}
class Program
{
static void Main(string[] args)
{
Car newCar = new Car(100, 50); //вызов конструктора с параметрами
}
}
Ключевое слово this
В примере выше используется ключевое слово this.
Указатель this - это указатель на объект, для которого был вызван нестатический метод. Ключевое слово this обеспечивает доступ к текущему экземпляру класса. Классический пример использования this, это как раз в конструкторах, при одинаковых именах полей класса и аргументов конструктора. Ключевое слово this это что-то вроде имени объекта, через которое мы имеем доступ к текущему объекту.
Несколько конструкторов
В классе возможно указывать множество конструкторов, главное чтобы они отличались сигнатурами. Сигнатура, в случае конструкторов, - это набор аргументов. Например, нельзя создать два конструктора, которые принимают два аргумента типа int.
Пример использования нескольких конструкторов:
class Car
{
private double mileage;
private double fuel;
public Car()
{
mileage = 0;
fuel = 0;
}
public Car(double mileage, double fuel)
{
this.mileage = mileage;
this.fuel = fuel;
}
}
class Program
{
static void Main(string[] args)
{
Car newCar = new Car(); // создаем автомобиль с параметрами по умолчанию, 0 и 0
Car newCar2 = new Car(100, 50); // создаем автомобиль с указанными параметрами
}
}
Если в классе определен один или несколько конструкторов с параметрами, мы не сможем создать объект через неявный конструктор по умолчанию:
class Car
{
private double mileage;
private double fuel;
public Car(double mileage, double fuel)
{
this.mileage = mileage;
this.fuel = fuel;
}
}
class Program
{
static void Main(string[] args)
{
Car newCar = new Car(100, 50);
Car newCar2 = new Car(); // ошибка, в классе не определен конструктор без параметров
}
}
Домашнее задание
Создайте класс Студент, определите в нем поля: имя, курс, есть ли у него стипендия. Создайте в классе несколько конструкторов, для возможности задания сразу всех указанных параметров или нескольких при создании экземпляров.
PS. Буду очень благодарен, если поделитесь с друзьями этой статьей с помощью кнопок социальных сетей в конце поста.Свойства в Си-шарп. Аксессоры get и set. Автоматические свойства В этом уроке мы продолжим рассматривать члены классов, и на очереди у нас свойства.
Свойство в Си-шарп – это член класса, который предоставляет удобный механизм доступа к полю класса (чтение поля и запись). Свойство представляет собой что-то среднее между полем и методом класса. При использовании свойства, мы обращаемся к нему, как к полю класса, но на самом деле компилятор преобразовывает это обращение к вызову соответствующего неявного метода. Такой метод называется аксессор (accessor). Существует два таких метода: get (для получения данных) и set (для записи). Объявление простого свойства имеет следующую структуру:
[модификатор доступа] [тип] [имя_свойства]
{
get
{
// тело аксессора для чтения из поля
}
set
{
// тело аксессора для записи в поле
}
}
Приведу пример использования свойств. Имеется класс Студент, и в нем есть закрытое поле курс, которое не может быть ниже единицы и больше пяти. Для управления доступом к этому полю будет использовано свойство Year:
class Student
{
private int year; //объявление закрытого поля
public int Year //объявление свойства
{
get // аксессор чтения поля
{
return year;
}
set // аксессор записи в поле
{
if (value < 1)
year = 1;
else if (value > 5)
year = 5;
else year = value;
}
}
}
class Program
{
static void Main(string[] args)
{
Student st1 = new Student();
st1.Year = 0; // записываем в поле, используя аксессор set Console.WriteLine(st1.Year); // читаем поле, используя аксессор get, выведет 1
Console.ReadKey();
}
}
Проще говоря, в свойстве реализуются два метода. В теле аксессора get может быть более сложная логика доступа, но в итоге должно возвращаться значение поля, либо другое значение с помощью оператора return. В аксессоре set же присутствует неявный параметр value, который содержит значение, присваиваемое свойству (в примере выше, при записи, значение value равно «0»).
Зачем это нужно?
Если, например, мы бы просто сделали поле year открытым и не использовали ни методы, ни свойство для доступа, мы могли бы записать в это поле любое значение, в том числе и некорректное, а так мы можем контролировать чтение и запись.
Для контроля доступа мы могли бы здесь использовать простые методы, но для этого нам бы пришлось реализовать два отдельных метода, с разными именами, и при обращении к ним необходимо использовать скобки, что добавляет лишние неудобства. Вот как бы выглядела та же программа с использованием методов (на практике используйте свойства):
class Student
{
private int year;
public int GetYear()
{
return year;
}
public void SetYear(int value)
{
if (value < 1)
year = 1;
else if (value > 5)
year = 5;
else year = value;
}
}
class Program
{
static void Main(string[] args)
{
Student st1 = new Student();
st1.SetYear(0);
Console.WriteLine(st1.GetYear());
Console.ReadKey();
}
}
Свойство также может предоставлять доступ только на чтение поля или только на запись. Если, например, нам необходимо закрыть доступ на запись, мы просто не указываем аксессор set. Пример:
class Student
{
private int year;
public Student(int y) // конструктор
{
year = y;
}
public int Year
{
get
{
return year;
}
}
}
class Program
{
static void Main(string[] args)
{
Student st1 = new Student(2);
Console.WriteLine(st1.Year); // чтение
st1.Year = 5; // ошибка, свойство только на чтение
Console.ReadKey();
}
}
Стоит помнить, что само свойство не определяет место в памяти для хранения поля, и, соответственно, необходимо отдельно объявить поле, доступом к которому будет управлять свойство.
Автоматические свойства
Автоматическое свойство – это очень простое свойство, которое, в отличии от обычного свойства, уже определяет место в памяти (создает неявное поле), но при этом не позволяет создавать логику доступа. Структура объявления Автоматического свойства:
[модификатор доступа] [тип] [имя_свойства] { get; set; }
У таких свойств, у их аксессоров отсутствует тело. Пример использования:
class Student
{
public int Year { get; set; }
}
class Program
{
static void Main(string[] args)
{
Student st1 = new Student();
st1.Year = 0;
Console.WriteLine(st1.Year);
Console.ReadKey();
}
}
Автоматически реализуемые свойства есть смысл использовать тогда, когда нет необходимости накладывать какие-либо ограничения на возможные значения неявного поля свойства.
И тут у вас может возникнуть вопрос, а в чем тогда разница между простыми открытыми полями и автоматическими свойствами. У таких свойств остается возможность делать их только на чтение или только на запись. Для этого уже используется модификатор доступа private перед именем аксессора:
public int Year { private get; set; } // свойство только на запись
public int Year { get; private set; } // свойство только на чтение
Домашнее задание
Создайте класс Телевизор, объявите в нем поле громкость звука, для доступа к этому полю реализуйте свойство. Громкость может быть в диапазоне от 0 до 100.
PS. Не забудьте поделиться с друзьями этой статьей с помощью кнопок социальных сетей.