Чтение онлайн

ЖАНРЫ

Интернет-журнал "Домашняя лаборатория", 2007 №9
Шрифт:

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;

ars[i] += i.ToString+1;

Console.WriteLine("ard[" +i + "]=" +ard[i] + "; ars[" +i + "]=" +ars[i]);

}

Заметьте, в этом фрагменте переменная аn обязана быть инициализированной, а массивы ard и ars не инициализируются и спокойно участвуют в вычислениях.

Еще раз о семантике присваивания

Подводя итоги рассмотрения присваивания х=е, следует отметить, что семантика присваивания далеко не столь проста, как может показаться с первого взгляда. Напомню, что деление типов на значимые и ссылочные приводит к двум семантикам присваивания. Будет ли семантика значимой или ссылочной — определяется типом левой части присваивания. Переменные значимых типов являются единоличными владельцами памяти, в которой хранятся их значения. При значимом присваивании память для хранения значений остается той же — меняются лишь сами значения, хранимые в ней. Переменные ссылочных типов (объекты) являются ссылками на реальные объекты динамической памяти. Ссылки могут разделять одну и ту же область памяти — ссылаться на один и тот же объект. Ссылочное присваивание — это операция над ссылками. В результате ссылочного присваивания ссылка начинает указывать на другой объект.

Рассмотрим объявления:

int x=3, y=5;

object obj1, obj 2;

Здесь объявлены четыре сущности: две переменные значимого типа и две — объектного. Значимые переменные х и у проинициализированы и имеют значения, объектные

переменные obj1 и obj2 являются пустыми ссылками со значением void. Рассмотрим присваивания:

obj1 = х; obj2 = у;

Эти присваивания ссылочные (из-за типа левой части), поэтому правая часть приводится к ссылочному типу. В результате неявного преобразования — операции boxing — в динамической памяти создаются два объекта, обертывающие соответственно значения переменных х и у. Сущности obj1 и obj2 получают значения ссылок на эти объекты.

Класс Math и его функции

Кроме переменных и констант, первичным материалом для построения выражений являются функции. Большинство их в проекте будут созданы самим программистом, но не обойтись и без встроенных функций. Умение работать в среде Visual Studio.Net предполагает знание встроенных возможностей этой среды, знание возможностей каркаса Framework.Net, пространств имен, доступных при программировании на языке С#, а также соответствующих встроенных классов и функций этих классов. Продолжим знакомство с возможностями, предоставляемыми пространством имен System. Мы уже познакомились с классом Convert этого пространства и частично с классом Console. Давайте рассмотрим еще один класс — класс Math, содержащий стандартные математические функции, без которых трудно обойтись при построении многих выражений. Этот класс содержит два статических поля, задающих константы E и PI, а также 23 статических метода. Методы задают:

• тригонометрические функции — Sin, Cos, Tan;

• обратные тригонометрические функции — ASin, ACcos, ATan, ATan2 (sinx, cosx);

• гиперболические функции — Tanh, Sinh, Cosh;

• экспоненту и логарифмические функции — Exp, Log, Log10;

модуль, корень, знак — Abs, Sqrt, Sign;

• функции округления — Ceiling, Floor, Round;

• минимум, максимум, степень, остаток — Min, Max, Pow, IEEERemainder.

В особых пояснениях эти функции не нуждаются. Приведу пример:

/// <summary>

/// работа с функциями класса Math

/// </summary>

public void MathFunctions

{

double a, b,t,t0,dt,y;

string NameFunction;

Console.WriteLine("Введите имя F(t)исследуемой функции

a*F(b*t)" + " (sin, cos, tan, cotan)");

NameFunction = Console.ReadLine;

Console.WriteLine("Введите параметр a (double)");

a= double.Parse(Console.ReadLine );

Console.WriteLine("Введите параметр b (double)");

b= double.Parse(Console.ReadLine);

Console.WriteLine("Введите начальное время t0(double)");

t0= double.Parse(Console.ReadLine);

const int points = 10;

dt = 0.2;

for(int i = 1; i<=points; i++)

{

t = t0 + (i-1)* dt;

switch (NameFunction)

{

case ("sin"):

у = a*Math.Sin(b*t);

break;

case ("cos"):

у = a*Math.Cos(b*t);

break;

Поделиться с друзьями: