// Все это хорошо, но такая избыточность…
class Test {
public int myInt;
public string myString;
public Test() {myInt = 9;}
public Test(string s) {
myInt = 9;
myString = s;
}
}
Альтернативой может быть определение вспомогательной функции, вызываемой всеми конструкторами. При этом уменьшается общее число повторений для операции присваивания, но теперь возникает следующая избыточность,
// Все равно остается избыточность…
class Test {
public int myInt;
public string myString;
public Test() {InitData();}
public Test(string s) {
myString = s;
InitData();
}
private void InitData() {myInt = 9;}
}
Оба эта подхода вполне легитимны, но в C# позволяется назначать членам типа начальные значения в рамках деклараций (вы, наверное, знаете, что другие объектно-ориентированные языки [например, C++], не позволяют такую инициализацию членов). В следующем фрагменте программного кода обратите внимание на то, что инициализация может выполняться и для внутренних объектных ссылок, а не только для числовых типов данных.
// Если нужно отказаться от значений, предусмотренных по умолчанию,
// эта техника позволяет избежать повторной записи программного
// хода инициализации в каждом конструкторе.
class Test {
public int myInt = 9;
public string myStr = "Мое начальное значение. ";
public SportsCar viper = new SportsCar(Color.Red);
...
}
Замечание. Инициализация членов выполняется до выполнения программной логики конструктора. Если присвоить значение полю в самом конструкторе, это сведет на нет инициализацию члена.
Итак, вы знаете, как объявить переменные класса. Теперь давайте выясним, как определить данные, изменить которые не предполагается. Для определения переменных с фиксированным, неизменяемым значением в C# предлагается ключевое слово const. После определения значения константы любая попытка изменить это значение приводит к ошибке компиляции. В отличие От C++, в C# ключевое слово const нельзя указывать для параметров и возвращаемых значений – оно предназначено для создания локальных данных и данных уровня экземпляра.
Важно понимать, что значение, присвоенное константе, во время компиляции уже должно быть известно, поэтому константу нельзя инициализировать объектной ссылкой (значение последней вычисляется в среде выполнения). Чтобы проиллюстрировать использование ключевого слова const, рассмотрим следующий тип класса.
class ConstData {
// Значение, присваиваемое константе, должно быть известно во время компиляции.
public const string BestNbaTeam = "Timberwolves";
public const double SimplePI = 3.14;
public const bool Truth = true;
public const bool Falsity = !Truth;
}
Обратите внимание на то, что значения всех констант известны во время компиляции. И действительно, если просмотреть эти константы с помощью ildasm.exe, то вы обнаружите, что их значения будут "жестко" вписаны в компоновочный блок, как показано на рис. 3.8. (Ничего более постоянного получить невозможно!)
Рис. 3.8. Ключевое слово const вписывает "свое" значение прямо в метаданные компоновочного блока
Если нужно сослаться на константу, определенную внешним типом, вы должны добавить префикс имени типа (например, ConstData.Truth), поскольку поля-константы являются неявно статическими. Однако при ссылке на константу, определенную в рамках текущего типа (или в рамках текущего члена), указывать префикс имени типа не требуется. Чтобы пояснить это, рассмотрим следующий класс.
class Program {
public const string BestNhlTeam = "Wild";
static void Main(string[] args) {
// Печать значений констант, определенных другими типами.
Console.WriteLine("Константа Nba: {0}", ConstData.BestNbaTeam);
Console.WriteLine("Константа SimplePI: {0}", ConstData.SimplePI);
Console.WriteLine("Константа Truth: {0}", ConstData.Truth);
Console.WriteLine("Константа Falsity: {0}", ConstData.Falsity);
// Печать значений констант члена.
Console.WriteLine("Константа Nhl: {0}", BestNhlTeam);
// Печать значений констант локального уровня.
const int LocalFixedValue = 4;
Console.WriteLine("Константа Local: {0}", LocalFixedValue);
Console.ReadLine();
Читать дальше