Читайте также: |
|
Запустите проект. У вас должны быть выполнены абсолютно все задания.
Откройте программный код окна. Нам предстоит проанализировать содержимое метода-обработчика button1_Click. Это достаточно длинный текст. Но он правильный, обеспечивает удобную работу пользователя - и в этом смысле (от пользователя) никаких претензий к программисту нет. А вот у программиста к себе самому - есть.
Когда «сплошной» программный текст достаточно большой, то он становится трудно понимаемым. Особенно со временем - чем больше проходит времени с момента его написания, тем меньше остается в памяти. Текст не должен быть очень большим. Текст можно уменьшить, если разбить его на отдельные подпрограммы (маленькие программы), дать этим подпрограммам имена и обращаться к ним, когда надо, с помощью всего одной команды.
В C# такие подпрограммы, выделенные программистом, называются функциями (или методами).
Попробуем перестроить текст обработчика, выделив из него отдельные фрагменты как функции. Вынесем в отдельную функцию следующую группу:
try
{ a = Convert.ToDouble(textBox1.Text);
b = Convert.ToDouble(textBox2.Text);
c = Convert.ToDouble(textBox3.Text);
}
catch
{ MessageBox.Show("проверьте исходные данные"); return;
}
Смысл группы тоже понятен: преобразование исходных строковых данных в численные значения. Назовем эту функцию Преобразование. Однако, простого вынесения операторов будет недостаточно. Дело в том, что результат работы этого блока двоякий. Может быть нормальное завершение, когда все данные - численные. Но возможен и второй вариант - если выработается исключение. Следовательно, надо предусмотреть оба варианта завершения функции. Как?
Например, так. Пусть функция при нормальном завершении выработает значение «истина», а при втором варианте - значение «ложь». В обработчике мы вызовем эту функцию, а после её завершения проверим, что она выработала (говорят, вернула). Следовательно, функция будет возвращать значение типа bool, т. е. тип функции будет уже не void, а bool. Запишем проект нашей функции сразу перед обработчиком в таком виде:
private bool Преобразование()
{ try
{ a = Convert.ToDouble(textBox1.Text);
b = Convert.ToDouble(textBox2.Text);
c = Convert.ToDouble(textBox3.Text);
}
catch
{ MessageBox.Show("проверьте исходные данные"); return;
}
}
Все вынесенные команды удалим из обработчика, а вместо них запишем такой оператор:
if (Преобразование() == false) return;
Смысл этого оператора таков: если в результате работы функции вернулось значение «ложь», то это значит, что в данных есть ошибка и надо завершить работу обработчика оператором return (возврат). Попробуем запустить программу. Увы, мы получим несколько ошибок (рис. 19). Три первых ошибки имеют одну и ту же природу. Текст пояснения к ошибке говорит о том, что переменные не определены внутри функции Преобразование.
Рис. 19. Окно ошибок
В самом деле, эти переменные объявлены внутри обработчика. Мы же теперь так построили работу, что значения в эти переменные должны сформироваться внутри другой функции (Преобразование), и эти значения должны быть переданы из неё в обработчик. Сформированные значения - это выход функции Преобразование. В этом случае надо использовать выходные параметры. Исправим заголовок функции и укажем список из трех выходных параметров:
private bool Преобразованием double a, out double b, out double c) Но раз изменился заголовок, то надо изменить и оператор вызова:
if (Преобразование(out a, out b, out c) == false) return;
Теперь мы можем быть уверены, что если значения сформируются в функции Преобразование, то они будут переданы в переменные a, b, и c в обработчик.
Вновь попробуем запустить программу. И снова ошибка, зато какая интересная! Обратите внимание: под подозрение компилятора попала теперь уже вся функция. В сообщении об ошибке говорится, что не все варианты исполнения функции завершаются возвратом значения. Верно, имеется два варианта. Один вариант, когда преобразование не выполнено, мы завершим оператором return false; А другой вариант, когда всё нормально? Добавим и туда оператор возврата, но уже вернём «истину» (показан фрагмент):
try
{ a = Convert.ToDouble(textBoxl.Text);
b = Convert.ToDouble(textBox2.Text);
c = Convert.ToDouble(textBox3.Text); return true;
}
Снова выполним компиляцию и получим уже три ошибки, имеющих одинаковую природу. Выходные параметры должны ОБЯЗАТЕЛЬНО получать какие-то значения. А если будет выработано исключение? Компилятор это «заметил». Давайте для успокоения души компилятора присвоим переменным какие-либо значения. Например, нулевые, в самом начале функции (показан фрагмент): private bool Преобразованием double a, out double b, out double c)
{ a = 0; b = 0; c = 0;
try
Исправим и вновь запустим программу. Теперь всё в порядке!
Следующий большой фрагмент текста (при a==0):
if (b==0)
{label5.Text = "решения нет"; label8.Text= "";}
else
{ x1 = (-c) /b; label8.Text=string.Format("{0,10:##.##}",x1);
label5.Text = "один корень";
}
label9.Visible = false; label6.Visible = false; label11.Visible = false; label10.Visible = false; label7.Visible = false;
Поступим мудрее, чем в прошлый раз: сначала проанализируем, а уж потом будем выносить код в функцию. Итак, что тут делается? Вычисляется x1. Значит, это будет выходной параметр. На основании чего вычисляется? На основании b и c. Значит, эти значения должны быть переданы в новую функцию. Следовательно, будет три параметра: два обычных (значения) и один выходной (out). Возвращать функция ничего не будет. Значит, тип функции void. Назовём функцию Линейное. Итак:
private void Линейное(double b, double c, out double x1)
{ if (b==0)
{ label5.Text = "решения нет "; label8.Text= "";}
else
{ x1 = (-c) /b; label8.Text=string.Format("{0,10:##.##}",x1);
label5.Text = "один корень";
}
label9.Visible = false; label6.Visible = false;
label11.Visible = false; label10.Visible = false;
label7. Visible = false;
}
Вместо вынесенного текста - один оператор:
Линейное (b, c, out xl);
Запускаем программу. Опять работает!
Ну, а теперь вынесем в отдельную функцию всю логику решения квадратного уравнения, т. е. весь текст из ветви else. Начинаем рассуждать. Очевидно, что в данном алгоритме используются для вычисления все коэффициенты. Это будут параметры-значения. Далее, формируются результаты xl и x2 - это будут выходные параметры. Функция всё вычисляет и «рассовывает» по объектам label, то есть ей просто нечего возвращать - значит, тип void. Присвоим ей имя - Квадратное. Итак, заголовок: private void Квадратное(double a, double b, double c, out double xl,
out double x2)
Соответственно, вызов функции:
Квадратное(a, b, c, out xl, out x2);
Запускаем! Восемь ошибок! Но... всё это уже мелочь. Первые семь ошибок связаны с переменной d. Правильно, она же в новой функции не объявлена. Объявляем в самом начале функции:
double d;
А восьмая ошибка... и не ошибка вовсе - это предупреждение. Кликнем по тексту ошибки дважды и увидим, что компилятор «придрался» к объявлению этой переменной в обработчике. В самом деле, переменная объявлена, но нигде не используется. Так давайте её удалим.
Запускаем! И вновь видим: не по всем веткам алгоритма выходные переменные получают значения (а должны). Дадим им в самом начале нулевые значения (фрагмент):
double d;
xl = 0; x2 = 0;
d = b * b - 4 * a * c;
И вновь запускаем программу. Наконец-то всё.
Так чего же ради мы мучались? А посмотрите на метод-обработчик: он совсем крохотный стал. И понятный. Правда, функций стало больше, но опять-таки каждая - небольшая и понятная. Ну, можно было бы еще разделить на части функцию Квадратное... А почему бы и нет!?
Дата добавления: 2015-08-09; просмотров: 111 | Нарушение авторских прав
<== предыдущая страница | | | следующая страница ==> |
ЧАСТЬ 1. Разработка алгоритма программы | | | Разработка некоторых элементов класса данных |