С другой стороны, хотя используются ссылки Employee, мы всегда выбираем правильную версию метода ToString(). Если указанный объект является объектом Manager, то при вызове метода ToString() для этого объекта будет выполняться версия метода ToString(), определенная в классе Manager. В этом состоит достоинство перезагрузки методов в C#. Можно заменить некоторые методы в производном классе и знать, что независимо от того, какой ссылочный тип используется для доступа к этому объекту, для него всегда будет выполняться правильный метод.
Давайте теперь рассмотрим странный синтаксис цикла for. Этот цикл является эквивалентом C# для следующего кода VB:
Integer I
For I = 1 То 3
listBox1.Items.Add "Details of the Employee"
Next
Идея цикла For в VB состоит в том, что он начинается с инициализации некоторой переменной — управляющей переменной цикла, и каждый раз при проходе цикла что-то добавляется к управляющей переменной, пока она не превысит конечное значение. Это достаточно полезно, но не дает почти никакой гибкости в работе цикла. Хотя можно изменять значение приращения или даже сделать его отрицательным, используя возможности Step, цикл всегда работает с помощью вычислений, и проверка на выход из цикла всегда происходит по достижении переменной некоторого минимального или максимального значения.
В C# цикл for обобщает эту концепцию. Базовая идея цикла for в C# следующая. В начале цикла что-то делается, на каждом шаге цикла тоже что-то делается, чтобы перейти к следующей итерации, затем, чтобы определить, когда выходить из цикла, выполняется некоторая проверка. Сравнение версий Visual Basic и C# выглядит следующим образом:
VB C#
В начале цикла Инициализация управляющей переменной цикла Выполнить что-то
Проверка на выход из цикла Не превысила ли переменная цикла некоторого значения? Проверка некоторого условия
В конце каждой итерации Увеличить управляющую переменную цикла Выполнить что-то
Это может выглядеть как-то неопределенно, но зато дает большую гибкость. Например, в C# вместо добавления некоторой величины к управляющей переменной цикла на каждой итерации можно добавлять какое-то число, которое считывается из файла и которое изменяется на каждой итерации. Проверка не должна быть проверкой значения управляющей переменной цикла, это может быть проверка, например, достижения конца файла. Это позволяет при подходящем выборе начального действия, проверки и действия в конце каждой итерации циклу for эффективно выполнять те же задачи, что и любому из циклов VB — For, Foreach, Do и While, или цикл может вообще работать неким экзотическим образом, для которого нет простого эквивалента в VB. Цикл for в C# действительно представляет полную свободу управления циклом в том виде, какой будет необходим для рассматриваемой задачи.
Надо отметить, что C# поддерживает также циклы foreach, do и while для соответствующих ситуаций.
Давайте вернемся к точному синтаксису. Вспомним, что версия C# для приведенного выше цикла for выглядит следующим образом:
for (int I = 0; I < 3; I++) {
this.listBox1.Items.Add(Employees[I].Name);
this.listBox1.Items.Add(Employees[I].ToString());
this.listBox1.Items.Add("");
}
Как можно видеть, инструкция for получает три различные элемента внутри скобок. Эти элементы разделяются точкой с запятой:
□ Первый элемент является действием, которое выполняется прямо в начале цикла, чтобы инициализировать цикл. В данном случае объявляется и инициализируется управляющая переменная цикла.
□ Следующим элементом является условие, определяющее завершение цикла. В данном случае условие состоит в том, что I должно быть меньше 3. Цикл продолжается, пока это условие будет true, и закончится, как только условие станет false. Условие оценивается в начале каждой итерации, чтобы, если оно окажется false в самом начале, инструкция внутри цикла вообще не выполнялась.
□ В третьем элементе находится инструкция, которая выполняется в конце каждой итерации цикла. Циклы Visual Basic всегда работают, увеличивая некоторое число, и это как раз то, что делается в данном случае.
Синтаксис выглядит незнакомым, но после привыкания к нему, можно использовать цикл for очень эффективно. Например, предположим, что необходимо вывести все целые степени 2, которые меньше 4000, в окне списка. Запишем следующий код:
for (int I = 2; I < 4000; I *= 2)
listBox1.Items.Add(I.ToString());
Такой результат можно получить и в VB, но немного труднее. Для этого конкретного цикла в VB лучше воспользоваться циклом while.
Мы закончили рассмотрение примеров. Оставшаяся часть приложения кратко рассматривает несколько свойств C#, о которых необходимо знать при выполнении перехода от VB к C#, и которые еще не рассматривались, в частности, некоторые из концепций C#, связанные с типами данных и операторами.
Как указывалось ранее, доступные в C# типы данных отличаются от типов данных, доступных в Visual Basic, лишь деталями. Но не только это, все типы данных в C# имеют свойства, которые обычно связываются с объектами. Например, как мы видели, каждый тип данных, даже простые типы, такие как int и float, поддерживает вызов методов (кстати, это свойство не вызывает никакой потери производительности).
Хотя типы данных, доступные в C#, слегка отличаются от типов данных в VB, все же большинство типов данных, знакомые из VB, имеют непосредственные эквиваленты в C#. Например, вместо Double из VB, C# имеет double, вместо Date из VB , C# имеет базовый класс .NET DateTime, который реализует огромное число методов и свойств, позволяющих извлекать или задавать даты с помощью различных форматов.
Одним исключением является Variant, для которого нет прямого эквивалента в C#. Тип данных Variant в VB является очень общим типом данных, который в некоторой степени существует только, чтобы поддерживать языки сценариев, которые не знают никаких других типов данных. Философия C#, однако, состоит в том, что язык является строго типизированным. Главная идея: если в каждом месте программы явно указывать используемый тип данных, то будет исключен один из основных источников ошибок времени выполнения. В связи с этим тип данных Variant в действительности не соответствует C#. Но все равно существуют ситуации, в которых необходимо ссылаться на переменную, не указывая тип этой переменной, и для этих случаев C# имеет тип данных object. object в C# очень похож на Object в VB. Однако в VB Object ссылается конкретно на объект COM и поэтому может использоваться только для ссылок на объекты, которые в терминологии VB означают ссылочные типы данных. Нельзя, например, использовать объектную ссылку для ссылки на Integer или на Single. В C#, напротив, объекты могут использоваться для ссылки на любой тип данных .NET, и так как в C# все типы данных являются типами данных .NET, это означает, что вы в праве преобразовать что угодно в object, включая int, float и все предопределенные типы данных. В этом смысле object в C# выполняет роль, аналогичную Variant в VB.
Типы данных значений и ссылочные типы данных
В Visual Basic существует четкое различие между типами данных значений и ссылочными типами данных. Типы данных значений включают большинство предопределенных типов данных: Integer, Single, Double и даже Variant (хотя строго говоря Variant может содержать также ссылку). Ссылочными типами данных являются любые объекты, включая определяемые модули классов и объекты ActiveX. Как можно было заметить из примеров в этом приложении, C# также делает различие между типами данных значений и ссылочными типами данных. Однако C# допускает больше гибкости, позволяя при определении класса найти, что этот класс будет типом данных значений. Это делается с помощью объявления класса структурой (struct). В той степени, насколько это касается C#, структура является по сути специальным типом класса, который представляется как значение, а не как ссылка. Накладные расходы, связанные с созданием экземпляров структур и их разрушением при завершении с ними работы меньше, чем связанные с созданием экземпляров и разрушением классов. Однако C# ограничивает свойства структур. В частности, нельзя выводить классы или другие структуры из структур. Причина этого состоит в том, что структуры предназначены для использования в качестве динамичных, простых объектов, для которых наследование в действительности не подходит. Фактически все предопределенные классы в C# — int, long, float, double являются на самом деле структурами .NET, вот почему на них можно вызывать такие методы, как ToString(). Тип данных string является, однако, ссылочным типом и поэтому в действительности является классом.