При использовании экземпляра класса, определенного с автоматическими свойствами, присваивать и получать значения можно с помощью вполне ожидаемого синтаксиса свойств:
using System;
using AutoProps;
Console.WriteLine("***** Fun with Automatic Properties *****\n");
Car c = new Car;
c.PetName = "Frank";
c.Speed = 55;
c.Color = "Red";
Console.WriteLine("Your car is named {0}? That's odd...",
c.PetName);
c.DisplayStats;
Console.ReadLine;
Автоматические
свойства и стандартные значения
Когда автоматические свойства применяются для инкапсуляции числовых и булевских данных, их можно использовать прямо внутри кодовой базы, т.к. скрытым поддерживающим полям будут присваиваться безопасные стандартные значения (
false
для булевских и
0
для числовых данных). Но имейте в виду, что когда синтаксис автоматического свойства применяется для упаковки переменной другого класса, то скрытое поле ссылочного типа также будет установлено в стандартное значение
null
(и это может привести к проблеме, если не проявить должную осторожность).
Добавьте к текущему проекту новый файл класса по имени
Garage
(представляющий гараж), в котором используются два автоматических свойства (разумеется, реальный класс гаража может поддерживать коллекцию объектов
Car
; однако в данный момент проигнорируем такую деталь):
namespace AutoProps
{
class Garage
{
// Скрытое поддерживающее поле int установлено в О!
public int NumberOfCars { get; set; }
// Скрытое поддерживающее поле Car установлено в null!
public Car MyAuto { get; set; }
}
}
Имея стандартные значения C# для полей данных, значение
NumberOfCars
можно вывести в том виде, как есть (поскольку ему автоматически присвоено значение
0
). Но если напрямую обратиться к
MyAuto
, то во время выполнения сгенерируется исключение ссылки на
null
, потому что лежащей в основе переменной-члену типа
Car
не был присвоен новый объект.
Garage g = new Garage;
// Нормально, выводится стандартное значение 0.
Console.WriteLine("Number of Cars: {0}", g.NumberOfCars);
// Ошибка во время выполнения!
// Поддерживающее поле в данный момент равно null!
Console.WriteLine(g.MyAuto.PetName);
Console.ReadLine;
Чтобы решить проблему, можно модифицировать конструкторы класса, обеспечив безопасное создание объекта. Ниже показан пример:
class Garage
{
// Скрытое поддерживающее поле установлено в 0!
public int NumberOfCars { get; set; }
// Скрытое поддерживающее поле установлено в null!
public Car MyAuto { get; set; }
// Для переопределения стандартных значений, присвоенных скрытым
//
поддерживающим полям, должны использоваться конструкторы.
public Garage
{
MyAuto = new Car;
NumberOfCars = 1;
}
public Garage(Car car, int number)
{
MyAuto = car;
NumberOfCars = number;
}
}
После такого изменения объект
Car
теперь можно помещать в объект
Garage
:
Console.WriteLine("***** Fun with Automatic Properties *****\n");
// Создать объект автомобиля.
Car c = new Car;
c.PetName = "Frank";
c.Speed = 55;
c.Color = "Red";
c.DisplayStats;
// Поместить автомобиль в гараж.
Garage g = new Garage;
g.MyAuto = c;
// Вывести количество автомобилей в гараже
Console.WriteLine("Number of Cars in garage: {0}", g.NumberOfCars);
// Вывести название автомобиля.
Console.WriteLine("Your car is named: {0}", g.MyAuto.PetName);
Console.ReadLine;
Инициализация автоматических свойств
Наряду с тем, что предыдущий подход работает вполне нормально, в версии C# 6 появилась языковая возможность, которая содействует упрощению способа присваивания автоматическим свойствам их начальных значений. Как упоминалось ранее в главе, полю данных в классе можно напрямую присваивать начальное значение при его объявлении. Например:
class Car
{
private int numberOfDoors = 2;
}
В похожей манере язык C# теперь позволяет присваивать начальные значения лежащим в основе поддерживающим полям, которые генерируются компилятором. В результате смягчаются трудности, присущие добавлению операторов кода в конструкторы класса, которые обеспечивают корректную установку данных свойств.
Ниже приведена модифицированная версия класса
Garage
с инициализацией автоматических свойств подходящими значениями. Обратите внимание, что больше нет необходимости в добавлении к стандартному конструктору класса логики для выполнения безопасного присваивания. В коде свойству
MyAuto
напрямую присваивается новый объект
Car
.
class Garage
{
// Скрытое поддерживающее поле установлено в 1.
public int NumberOfCars { get; set; } = 1;
// Скрытое поддерживающее поле установлено в новый объект Car.