Программирование / Заочники / Инфорамтика и программирование / Методичка (1 сем) / Урок 10 - Switch..case
.pdfУрок 10: Оператор switch..case.
Основная цель урока.
1.Изучить работу с оператором switch...case
2.Научиться использовать вспомогательные булевские переменные
3.Продолжить изучение функций\процедур
.
Учебное задание 2.2.
Разработать систему авторизации пользователя (вход в систему, проверка пароля,
сброс пароля, установка пароля).
Технология выполнения учебного задания 2.2.
Шаг 1. Создайте новый проект консольного приложения, назовите его Lab2.2.
Шаг 2. Для начала нужно придумать, где и в каком виде будет храниться пароль пользователя.
Где хранить пароль? Пароль можно хранить в файле, базе данных, на удалённом сервере или использовать пользовательские настройки (Settings)
проекта. В данной работе мы будем использовать свойства проекта.
В каком виде хранить пароль? Пароль можно хранить в открытом виде, однако очевидно, что это совершенно небезопасно. Обычно хранят не сам пароль, а хэш-
сумму пароля. Даже если хэш-сумма будет получена злоумышленником,
восстановить пароль из хэша можно только путём полного перебора всех паролей.
Хэш-сумма – это уникальное (для CRC32 – 32 битное, для MD5 – 64 битное)
значение, вычисленное из некоторых исходных данных. Исходными данными может быть пароль, некоторое сообщение, файл. Например, в пиринговых сетях (в.т.ч.
торренты) вычисленные хэш-суммы от файлов позволяют однозначно идентифицировать файлы без их побайтового сравнения.
Для определения хэш-суммы пароля, будет использовать метод GetHashCode.
Добавьте в проект новую пользовательскую настройку (Setting), задайте имя
PasswordHash , тип данных int, значение 0 (это делали в уроке 5, учебное задание
1.5).
Шаг 3. Напишем основной каркас программы.
Если хэш-сумма пароля равна 0 (дефолтовое значение), значит пароль не задан и мы запрашиваем у пользователя ввод нового пароля (с подтверждением).
Иначе – в ветке else запрашиваем ввод пароля и сравниваем хэши паролей. Для
получения хэша используем метод GetHashCode (этот метод есть у всех типов
данных).
static void Main(string[] args)
{
// получаем хэш из пользовательских настроек
int hashPassword = Properties.Settings.Default.PasswordHash;
// если хэш нулевой - значит пароль не установлен if (hashPassword.GetHashCode() == 0)
{
// установка нового пароля
Console.WriteLine("Пароль не задан, введите новый пароль:"); string newPass = Console.ReadLine(); Console.WriteLine("Введите подтверждение пароля:");
string newPass2 = Console.ReadLine(); if (newPass == newPass2)
{
Properties.Settings.Default.PasswordHash = newPass.GetHashCode();
Properties.Settings.Default.Save(); Console.WriteLine("Пароль успешно установлен!");
}
else
{
Console.WriteLine("Ошибка! Пароли не совпадают!");
}
}
else
{ // иначе - хэш не нулевой, значит пароль уже задан
Console.WriteLine("Введите пароль:"); string pass = Console.ReadLine();
// сравниваем хэш коды паролей
if (pass.GetHashCode() == hashPassword)
{
Console.Clear();
Console.WriteLine("Вход в систему произведён.");
}
else
{
Console.WriteLine("Неверный пароль!");
}
}
Console.WriteLine("Работа программы завершена, нажмите любую клавишу...");
Console.ReadKey();
}
Листинг 1
Шаг 4. Запустите программу, нажав клавишу F5, проверьте её на
работоспособность.
Шаг 5. Добавим возможность ввода команд и сброса пароля (командой reset) после входа в систему.
На этом шаге воспользуемся конструкцией switch…case.
Конструкция switch..case используется, когда проверить переменную на равенство целому ряду значений. Конструкция switch..case может быть заменена многострочным оператором if..elseif..else, однако в случаях, когда проверяется значение только 1-ой переменной\выражения (и этих значений достаточно много)
гораздо удобнее использовать конструкцию switch…case.
Общий синтаксис:
switch (Выражение)
{
case Значение1: // Код break;
case Значение2: // Код break;
case Значение3: // Код break;
default:
//остальные значения
//Код
break;
}
Пример:
int a = Convert.ToInt32(Console.ReadLine()); switch (a)
{
case 1:
Console.WriteLine("a = 1"); break;
case 2: case 3: case 5:
Console.WriteLine("a = 1 or 3 or 5"); break;
case 100:
Console.WriteLine("a = 100"); break;
default:
Console.WriteLine("a = ???"); break;
}
В листинге 2 приведён код, добавляющий возможность ввода команд и сброса пароля (командой reset) после входа в систему.
Console.Clear();
Console.WriteLine("Вход в систему произведён.");
// бесконечный цикл...
while (true)
{
Console.WriteLine("Введите команду:"); string command = Console.ReadLine();
//ToLower() - переводим в нихний регистр
//Trim() - удаляем пробелы справа и слева
//" a b c ".Trim() = "a b c" command = command.ToLower().Trim();
//если введена команда quit - выходим из цикла if (command == "quit") break;
switch (command)
{
case "reset": Properties.Settings.Default.PasswordHash = 0; Properties.Settings.Default.Save(); Console.WriteLine("Пароль успешно сброшен!"); break;
default:
Console.WriteLine("Неизвестная команда: " + command); break;
}
}
Листинг 2. Сброс пароля.
Шаг 6. Запустите программу, нажав клавишу F5, проверьте её на работоспособность. Попробуйте сбросить заданный пароль командой reset.
Шаг 7. Следующим шагом улучшим читабельность кода, выделив некоторые фрагменты в отдельные процедуры. Код, отвечающий за генерацию нового пароля логично выделить в процедуру GenerateNewPassword. Код, который идёт после успешной авторизации и фактически представляет собой некоторый полезный функционал программы, так же логично выделить в отдельную процедуру.
Создадим 2 новые процедуры GenerateNewPassword и CommandLoop, как показано в листинге 3.
static void GenerateNewPassword()
{
}
static void CommandLoop()
{
}
static void Main(string[] args)
{
// получаем хэш из пользовательских настроек
int hashPassword = Properties.Settings.Default.PasswordHash;
Листинг 3. Создание процедур GenerateNewPassword и CommandLoop.
Далее перемещаем весь код, отвечающий за генерацию нового пароля в процедуру GenerateNewPassword и код, отвечающий за обработку пользовательских команд, в процедуру CommandLoop (листинг 4). Теперь в процедуре Main, вместо когда генерации нового пароля можно просто вызвать процедуру
GenerateNewPassword (листинг 5).
static void GenerateNewPassword()
{
// установка нового пароля
Console.WriteLine("Пароль не задан, введите новый пароль:"); string newPass = Console.ReadLine(); Console.WriteLine("Введите подтверждение пароля:");
string newPass2 = Console.ReadLine(); if (newPass == newPass2)
{
Properties.Settings.Default.PasswordHash = newPass.GetHashCode(); Properties.Settings.Default.Save();
Console.WriteLine("Пароль успешно установлен!");
}
else
{
Console.WriteLine("Ошибка! Пароли не совпадают!");
}
}
static void CommandLoop()
{
// бесконечный цикл...
while (true)
{
Console.WriteLine("Введите команду:"); string command = Console.ReadLine();
//ToLower() - переводим в нихний регистр
//Trim() - удаляем пробелы справа и слева
//" a b c ".Trim() = "a b c"
command = command.ToLower().Trim();
// если введена команда quit - выходим из цикла if (command == "quit") break;
switch (command)
{
case "reset": Properties.Settings.Default.PasswordHash = 0; Properties.Settings.Default.Save(); Console.WriteLine("Пароль успешно сброшен!"); break;
default:
Console.WriteLine("Неизвестная команда: " + command); break;
}
}
}
Листинг 4. Перемещение кода в процедуры GenerateNewPassword и CommandLoop.
static void Main(string[] args)
{
// получаем хэш из пользовательских настроек
int hashPassword = Properties.Settings.Default.PasswordHash;
// если хэш нулевой - значит пароль не установлен if (hashPassword.GetHashCode() == 0)
{
GenerateNewPassword();
}
else
{ // иначе - хэш не нулевой, значит пароль уже задан
Console.WriteLine("Введите пароль:"); string pass = Console.ReadLine();
// сравниваем хэш коды паролей
if (pass.GetHashCode() == hashPassword)
{
Console.Clear();
Console.WriteLine("Вход в систему произведён.");
CommandLoop();
}
else
{
Console.WriteLine("Неверный пароль!");
}
}
Console.WriteLine("Работа программы завершена, нажмите любую клавишу...");
Console.ReadKey();
}
Листинг 5. Замена фрагментов кода, на вызовы процедур.
Шаг 8. Текущая реализация авторизации достаточно поверхностная, не учитывается проверка сложности пароля (можно поставить пустой пароль или пароль 1), в случае неверно подтверждения пароля – работа программы просто завершается. Улучшим функционал процедуры GenerateNewPassword.
Добавим функцию, которая будет проверять сложность пароля. Если пароль подходит (достаточно сложный), функция должна возвращать только 2 значения – 1-
ое будет информировать вызывающий код о том, что пароль подходит, второе значение – что пароль не подходит (слишком простой).
В качестве типа возвращаемого значения логично будет использовать булевский тип данных (bool), который как раз может принимать одно из двух значений (true – истина и false – ложь).
Значение true (позитивное) будет использоваться для информирования о том,
что пароль прошёл проверку на сложность, false(негативное) – не прошел.
В качестве аргумента функция будет принимать пароль, который необходимо проверить.
Пока что ограничимся только проверкой на длину пароля. Пароль должен быть не менее 3-х символов. Добавьте код из листинга 6 на уровне класса Program.
class Program
{
//bool - тип возвращаемого значения
//string password - 1-ый аргумент(параметр) функции static bool CheckPassword(string password)
{
//Если Длина пароля Меньше 3=х символов - возвращаем false if (password.Length < 3) return false;
return true;
}
static void GenerateNewPassword()
{
Листинг 6. Создание функции CheckPassword.
Внесём так же изменения в процедуру GenerateNewPassword (листинг 7).
static void GenerateNewPassword()
{
// установка нового пароля
Console.WriteLine("Пароль не задан, введите новый пароль:"); string newPass = Console.ReadLine();
if (CheckPassword(newPass) == true)
{
Console.WriteLine("Введите подтверждение пароля:"); string newPass2 = Console.ReadLine();
if (newPass == newPass2)
{
Properties.Settings.Default.PasswordHash = newPass.GetHashCode();
Properties.Settings.Default.Save(); Console.WriteLine("Пароль успешно установлен!");
}
else
{
Console.WriteLine("Ошибка! Пароли не совпадают!");
}
}
else
{
Console.WriteLine("Введён слишком простой пароль.");
}
}
Листинг 7. Изменения в процедуре GenerateNewPassword.
Т.е. тот пароль, который пользователь вводит первый раз (newPass) предаётся в функцию CheckPassword в качестве аргумента функции password. И затем уже аргумент функции password проверяется на сложность.
Шаг 9. Следующим шагом зациклим работу функции GenerateNewPassword
таким образом, чтобы функция не завершалась, пока пользователь не введёт верно пароль и подтверждение. Сейчас в случае ошибки ("Ошибка! Пароли не совпадают!"
и "Введён слишком простой пароль.") процедура просто завершается и смены пароля не происходит.
Для реализации этого функционала будем использовать специальную переменную - флаг. Переменная - флаг – это, как правило, переменная логического типа значение который сигнализирует о состоянии вычислительного процесса.
Переменная bSuccess (Success с англ. « успех», b – стандартный префикс логических переменных) сигнализирует о успешной установке пароля, и пока она равна false – цикл будет выполняться (листинг 8).
static void GenerateNewPassword()
{
bool bSuccess = false;
// установка нового пароля (цикл выполняется до тех пор, //пока bSuccess равно false)
do
{
Console.WriteLine("Пароль не задан, введите новый пароль:"); string newPass = Console.ReadLine();
if (CheckPassword(newPass) == true)
{
Console.WriteLine("Введите подтверждение пароля:"); string newPass2 = Console.ReadLine();
if (newPass == newPass2)
{
Properties.Settings.Default.PasswordHash = newPass.GetHashCode();
Properties.Settings.Default.Save(); Console.WriteLine("Пароль успешно установлен!");
//если пароль успешно изменён устанавливаем
//переменную bSuccess в true
bSuccess = true;
}
else
{
Console.WriteLine("Ошибка! Пароли не совпадают!");
}
}
else
{
Console.WriteLine("Введён слишком простой пароль.");
}
} while (bSuccess == false);
}
Листинг 8. Изменения в процедуре GenerateNewPassword.
Шаг 10. Запустите программу, нажав клавишу F5, проверьте её на работоспособность.
Шаг 11. Усложним функцию проверки пароля.
Задание:
1.Пароль должен содержать не менее 3-х уникальных символов (т.е. пароли
8888 или 112211 или abbbaaba и.т.п. недопустимы)
2.Пароль должен содержать хотя бы 1 букву.
Для реализации пункта 1 создадим дополнительный список символов (char),
который будет содержать все уникальные символы пароля. Сначала он, конечно,
будет пустой, затем в цикле пробегаемся по всем символам пароля и проверяем содержится ли текущий символ в этом списке (методом Contains), если не содержится – добавляем его в список. В результате по завершению цикла мы получим список с уникальными символами пароля, затем достаточно просто сравнить количество элементов в списке (через св-во Count) с некоторым числом.
Для реализации пунка 2 будем использовать вспомогательную булевскую переменную-флаг (bHasLetters), которая будет сигнализировать о том, была ли найдена хотя бы одна буква. Для проверки является ли текущий символ буквой будем использовать метод char.IsLetter.
В листинге 9 приведён код, реализующий данный функционал.
static bool CheckPassword(string password)
{
// Если Длина пароля Меньше 3=х символов - возвращаем false if (password.Length < 3) return false;
//провека на повторяющиеся символы
//diffLetters - список уникальных символов пароля
List<char> diffLetters = new List<char>();
//bHasLetters - перменная сигнализирует о
//присутствии в пароле хотя бы 1-ой буквы
bool bHasLetters = false;
// пробегаемся по всем символам пароля...
for (int i = 0; i < password.Length; i++)
{
//текущий символ пароля (i-тый) char symbol = password[i];
//если diffLetters не содержит этот символ...
if (diffLetters.Contains(symbol) == false)
{
//...то добавлем его в список
diffLetters.Add(symbol);
}
// если текущий символ это буква
if (char.IsLetter(symbol)) bHasLetters = true;
}
if (bHasLetters == false) return false;
if (diffLetters.Count <= 3) return false;
return true;
}
Листинг 8. Изменения в процедуре CheckPassword.
Шаг 12. Запустите программу, нажав клавишу F5, проверьте её на
работоспособность.
Самостоятельное задание 2.2.
Усовершенствовать учебное задание следующим образом:
1.Усложнить проверку сложности пароля
∙Пароль не может содержать даты (для проверки можно пробовать преобразовать пароль в дату и если произойдёт исключение – отлавливать его, см. предыдущее задание, конструкцию try…catch)
∙Пароль не должен содержать знаков пробела
∙Пароль должен содержать не только буквы, но и хотя бы 1 цифру
2.Добавить подсказку к паролю (так же как хэш пароля сохраняется в пользовательских настройках (Settings) проекта).
Подсказка это некоторая строка, которая задаётся вместе с паролем и затем отображается при вводе пароля. Если подсказка не задана при генерации пароля (т.е. введена пустая строка), она не должна отображаться при запросе пароля.
Добавить проверку, чтобы подсказка не могла совпадать с паролем.
3. Добавить команды:
Название команды |
Описание |
|
|
cls |
Очистка экрана от сообщений |
|
|
newyear |
Количество дней оставшиеся до нового года |
|
|
