Страница 272 из 371
Условное выражение
В С#, как и в C++, разрешены условные выражения. Конечно, без них можно обойтись, заменив их условным оператором. Вот простой пример их использования, поясняющий синтаксис их записи:
//Условное выражение
int а = 7, Ь= 9, max;
max= (a>b)? a: b;
Console.WriteLine("a = " + a +"; b= " + b + "; max(a,b) = " + max);
Условное выражение начинается с условия, заключенного в круглые скобки, после которого следует знак вопроса и пара выражений, разделенных двоеточием": ". Условием является выражение типа bool. Если оно истинно, то из пары выражений выбирается первое, в противном случае результатом является значение второго выражения. В данном примере переменная max получит значение 9.
Операция приведения к типу
Осталось рассмотреть еще одну операцию — приведение к типу. Эта операция первого приоритета имеет следующий синтаксис:
(type) <унарное выражение>
Она задает явное преобразование типа, определенного выражением, к типу, указанному в скобках. Чтобы операция была успешной, необходимо, чтобы такое явное преобразование существовало. Напомню, существуют явные преобразования внутри арифметического типа, но не существует, например, явного преобразования арифметического типа в тип bool. При определении пользовательских типов для них могут быть заданы явные преобразования в другие, в том числе встроенные, типы. О явных преобразованиях говорилось достаточно много, приводились и примеры. Поэтому ограничусь совсем простым примером:
//cast
int р;
р = (int)x;
//Ь = (bool)x;
В данном примере явное преобразование из типа double в тип int выполняется, а преобразование double в тип bool приводит к ошибке, потому и закомментировано.
7. Присваивание и встроенные функции
Присваивание. Новинка C# — определенное присваивание. Классы Math, Random и встроенные функции.
Присваивание
В большинстве языков программирования присваивание — это оператор, а не операция. В языке C# присваивание унаследовало многие особенности присваивания языка C++. В C# оно толкуется как операция, используемая в выражениях. Однако в большинстве случаев присваивание следует рассматривать и использовать как обычный оператор.
Возьмем полезный случай реального использования присваивания как операции. В ситуации, называемой множественным присваиванием, списку переменных присваивается одно и тоже значение. Вот пример:
/// <summary>
/// анализ присваивания
/// </summary>
public void Assign()
{
double x,y,z,w =1, u =7, v= 5;
x=y=z=w=(u+v+w)/(u-v-w);
}//Assign
По мере изложения в метод Assign будут добавляться фрагменты кода, связанные с рассматриваемой темой присваивания.
О семантике присваивания говорилось уже достаточно много. Но следует внести еще некоторые уточнения. Правильно построенное выражение присваивания состоит из левой и правой части. Левая часть — это список переменных, в котором знак равенства выступает в качестве разделителя. Правая часть — это выражение. Выражение правой части вычисляется, при необходимости приводится к типу переменных левой части, после чего все переменные левой части получают значение вычисленного выражения. Последние действия можно рассматривать как побочный эффект операции присваивания. Заметьте, все переменные в списке левой части должны иметь один тип или неявно приводиться к одному типу. Операция присваивания выполняется справа налево, поэтому вначале значение выражения получит самая правая переменная списка левой части, при этом значение самого выражения не меняется. Затем значение получает следующая справа по списку переменная — и так до тех пор, пока не будет достигнут конец списка. Так что реально можно говорить об одновременном присваивании, в котором все переменные списка получают одно и то же значение. В нашем примере, несмотря на то, что переменная w первой получит значение, а выражение в правой части зависит от w, все переменные будут иметь значение 13.0. Рассмотрим еще один фрагмент кода:
bool b;
х=5; у=6;
//Ь= х=у;
//if (х=у) z=1;else z=-1;
В программе на языке C++ можно было снять комментарии с операторов, и этот фрагмент кода компилировался и выполнялся бы без ошибок. Другое дело, что результат мог быть некорректен, поскольку, вероятнее всего, операция присваивания "х=у" написана по ошибке и ее следует заменить операцией эквивалентности "х==у". в языке C# оба закомментированных оператора, к счастью, приведут к ошибке трансляции, поскольку результат присваивания имеет тип double, для которого нет неявного преобразования в тип bool. На C# такая программа будет выполняться, только если х и у будут иметь тип bool, но в этом случае, возможно, применение операции присваивания имеет смысл. С типами double корректная программа на C# может быть такой:
x =у;
Ь= (у! = 0);
if(у! = 0) z = 1; else z = -1;
В программе появился лишний оператор, но исчезла двусмысленность, порождаемая операцией присваивания.
Специальные случаи присваивания
В языке C++ для двух частных случаев присваивания предложен отдельный синтаксис. Язык C# наследовал эти полезные свойства. Для присваиваний вида "х=х+1", в которых переменная увеличивается или уменьшается на единицу, используются специальные префиксные и постфиксные операции "++" и Другой важный частный случай — это присваивания вида:
x = x <operator> (expression)
Для таких присваиваний используется краткая форма записи:
x <operator>= expression
В качестве операции разрешается использовать арифметические, логические (побитовые) операции и операции сдвига языка С#. Семантика такого присваивания достаточно очевидна, и я ограничусь простым примером:
х += u+v; у /=(u-v);
b &= (х<у);
Однако и здесь есть один подводный камень, когда х= х+а не эквивалентно х +=а. Рассмотрим следующий пример:
byte Ь3 = 21;
Ь3 +=1; //Это допустимо
//Ь3 = Ь3+1; //А это недопустимо: результат типа int
Закомментированный оператор приведет к ошибке компиляции, поскольку правая часть имеет тип int, а неявное преобразование к типу byte отсутствует. Следует понимать, что преимущество первой формы записи — только кажущееся: если при инициализации переменная b получит допустимое значение 255, то следующий оператор присваивания в краткой форме не выдаст ошибки, но даст неверный результат, а это — самое худшее, что может случиться в программе. Так что надежнее пользоваться полной формой записи присваивания, не экономя на паре символов.
Определенное присваивание
Присваивание в языке C# называется определенным присваиванием (definite assignment). В этом термине отражен тот уже обсуждавшийся факт, что все используемые в выражениях переменные должны быть ранее инициализированы и иметь определенные значения. Единственное, за чем компилятор не следит, так это за инициализацией переменных массива. Для них используется инициализация элементов, задаваемая по умолчанию. Приведу пример:
//определенное присваивание
int аn =0; //переменные должны быть инициализированы
for (int i= 0;i<5;i++)
{an =i + 1; }
x+=an; z+=an; у = an;
string[] ars = new string[3];
doublet] ard = new double[3];
for (int i= 0;i<3;i++)
{
//массивы могут быть без инициализации
ard[i] += i+1;