На собеседование в одной из фирм мне дали вот такое тестовое задание на знание основ c#. Надеюсь, оно и для вас не окажется сложным. Для тех кто хочет проверить себя, привожу решение этого задания.
Техническое задание
Требуется написать программу CalculateBonus для рассчета премии по следующей формуле:Bonus = Salary * SalaryProcent/100% * Koef
где:
Salary - зарплата сотрудника , целое число типа int
SalaryProcent - процент от зарплаты, предназначенный на выплату премии, типа byte
Koef - поправочный коэффиециент , типа double
Параметры передаются из командной строки в следующем формате:
обязательный параметр:
argv[0] string (разделенные запятой код сотрудника(отдел и должность) и фамилия)
опциональные параметеры:
argv[1] int, зарплата, если неуказана принимается равной 500
argv[2] byte процент от зарплаты, предназначенный на выплату премии, по умолчанию 10%.
argv[3] double поправочный коэффициент, по умолчанию 0.96.
Например:
CalculateBonus.EXE 12,Сидоров 650 10 0.90 - означает запрос на рассчет
премии для сотрудника отдела с кодом 1 (QA) занимающего должность с кодом 2(Manager) с фамилией Сидоров, зарплата которого 650, процент от зарплаты на выплату премии составляет 10%, поправочный коэффициент = 0.90.
CalculateBonus.EXE 01,Петров - означает запрос на рассчет премии для сотрудинка отдела с кодом 0, состоящего в должности 1. Значения для остальных параметров следует взять по умолчанию.
C суммы премии большей чем 10, должен быть списан налог в размере 13%. Данная функциональность реализуется отдельной функцией bool PayTax(ref decimal bonus, out int TaxRate)
уменьшающей сумму премии(параметр Bonus) на сумму налогов , возравращающей в параметре TaxRate ставку налога, возвращаемое значение типа bool показывает были ли вычтены налоги.
Программа должна генерировать отчет в следующем формате:
Сотрудник: ИВАНОВ (Фамилия сотрудника в верхнем регистре)
Должность: Manager (Должность сотрудника)
Отдел: QA (Отдел сотрудника)
Премия: 55,42 (Вычисленная премия)
Включая налог: 13 % (В случае же если премия составила < 10 и налог невзимался "Не включая налог: 13%")
Программа должна возращать cледующие значения
0 - если премия успешно была начислена
-1 - если не был передан обязательный(0й) аргумент
-2 - если указаный департамент не существует
-3 - если указанная должность не существует
Все допустимые значения возврата должны быть членами переисления ReturnCodes
Особенности реализации:
Существуют следующие отделы
RD = 0, //Отдел разработок
QA, //Отдел тестирования
Support, //Отдел технической поддержки
Sales, //Отдел продаж
Marketing, //Отдел маркетинга
Все допустимые коды отделов должны быть членами перечисления Departments.
Существвуют следующие должности
Employee = 0,
Lead,
Manager,
Director
Все допустимые коды должностей должны быть членами перечисления Ranks
Переменная для хранения итоговой премии(Bonus) должна быть обьявлена как decimal , при вычислениях потеря точности должна быть сведена к возможному миниму.
Разбор задания
Итак, приступим. Опишем сначала в перечислениях существующие в программе должности, отделы и ошибки, возвращаемые при некорректной работе программы./// <summary> /// Existing departments. /// </summary> public enum Departments { /// <summary> /// Development Department. /// </summary> RD = 0, //Отдел разработок /// <summary> /// Testing Department. /// </summary> QA, //Отдел тестирования /// <summary> /// Technical Support Department. /// </summary> Support, //Отдел технической поддержки /// <summary> /// Sales Department. /// </summary> Sales, //Отдел продаж /// <summary> /// Marketing Department. /// </summary> Marketing, //Отдел маркетинга } |
/// <summary> /// Existing ranks. /// </summary> public enum Ranks { /// <summary> /// Employee. /// </summary> Employee, /// <summary> /// Lead. /// </summary> Lead, /// <summary> /// Manager. /// </summary> Manager, /// <summary> /// Director. /// </summary> Director } |
/// <summary> /// Codes, which can returns the program. /// </summary> public enum ReturnCodes { /// <summary> /// Successfully. /// </summary> Ok = 0, /// <summary> /// Incorrectly arguments command line. /// </summary> ErrorArgs = -1, /// <summary> /// Id departments is not validate. /// </summary> ErrorDepartments = -2, /// <summary> /// Id ranks is not validate. /// </summary> ErrorRanks = -3 } |
/// <summary> /// Class provides the employee. /// </summary> public class Employee { /// <summary> /// The last name of employee. /// </summary> private string lastName; /// <summary> /// The reedonly properties of field lastName. /// </summary> public string LastName { get { return lastName; } } /// <summary> /// The department of employee. /// </summary> private Departments department; /// <summary> /// The reedonly properties of field department. /// </summary> public Departments Department { get { return department; } } /// <summary> /// The role of employee. /// </summary> private Ranks role; /// <summary> /// The reedonly properties of field role. /// </summary> public Ranks Role { get { return role; } } /// <summary> /// The bonus of employee. /// </summary> private decimal bonus; /// <summary> /// The properties of field bonus. /// </summary> public decimal Bonus { get { return bonus; } set { bonus = value; } } /// <summary> /// The salary of employee. /// </summary> private int salary; /// <summary> /// Percentage of salary, which accrue bonus. /// </summary> private byte percentOfSalary; /// <summary> /// Correction factor of bonus. /// </summary> private double correctionFactor; /// <summary> /// Constructor. /// </summary> /// <param name="department">ID departments.</param> /// <param name="role">ID ranks.</param> /// <param name="lastName">Last name.</param> /// <param name="salary">Salary.</param> /// <param name="percentOfSalary">% of salary to bonus.</param> /// <param name="correctionFactor">Correction factor.</param> public Employee(Departments department, Ranks role, string lastName, int salary, byte percentOfSalary, double correctionFactor) { this.department = department; this.role = role; this.lastName = lastName; this.salary = salary; this.percentOfSalary = percentOfSalary; this.correctionFactor = correctionFactor; } /// <summary> /// Constructor. /// </summary> /// <param name="department">ID departments.</param> /// <param name="role">ID ranks.</param> /// <param name="lastName">Last name.</param> /// <param name="salary">Salary.</param> /// <param name="percentOfSalary">% of salary to bonus.</param> public Employee(Departments department, Ranks role, string lastName, int salary, byte percentOfSalary) { this.department = department; this.role = role; this.lastName = lastName; this.salary = salary; this.percentOfSalary = percentOfSalary; this.correctionFactor = 0.96; } /// <summary> /// Constructor. /// </summary> /// <param name="department">ID departments.</param> /// <param name="role">ID ranks.</param> /// <param name="lastName">Last name.</param> /// <param name="salary">Salary.</param> public Employee(Departments department, Ranks role, string lastName, int salary) { this.department = department; this.role = role; this.lastName = lastName; this.salary = salary; this.percentOfSalary = 10; this.correctionFactor = 0.96; } /// <summary> /// Constructor. /// </summary> /// <param name="department">ID departments.</param> /// <param name="role">ID ranks.</param> /// <param name="lastName">Last name.</param> public Employee(Departments department, Ranks role, string lastName) { this.department = department; this.role = role; this.lastName = lastName; this.salary = 500; this.percentOfSalary = 10; this.correctionFactor = 0.96; } /// <summary> /// Calculating bonus. /// </summary> public void CulcBonus() { bonus = (decimal)((salary * percentOfSalary / 100) * correctionFactor); } } |
/// <summary> /// The Main class which contains the entry point. /// </summary> public class MainClass { /// <summary> /// The minimum bonus for the tax. /// </summary> public const int minBonusOfTax = 10; /// <summary> /// Tax Rate. /// </summary> public const int constTaxRate = 13; /// <summary> /// Entry point. /// </summary> /// <param name="args">Arguments command line. /// Command-line arguments to be set as follows:AB,C D E F /// where A - ID departments /// where В - ID ranks /// where С - last name /// where D - salary /// where E - % of salary to bonus /// where D - correction factor</param> /// <returns></returns> static public int Main(string[] args) { Employee employee = null; int role = 0; int department = 0; string[] strs = null; //Разбиваем первый аргумент на составляющие. try { strs = args[0].Split(','); if (strs.Length != 2) { Console.WriteLine("Входные параметры заданы неверно!"); return (int)ReturnCodes.ErrorArgs; } department = Int32.Parse(strs[0].Substring(0, 1)); role = Int32.Parse(strs[0].Substring(1, 1)); } #region CatchBlock catch (IndexOutOfRangeException exIndex) { Console.WriteLine("Не заданы параметры командной строки!"); return (int)ReturnCodes.ErrorArgs; } catch (Exception ex) { Console.WriteLine("Не верный формат входных параметров!"); Console.WriteLine("Формат должен быть следующим: AB,C D E F "); Console.WriteLine("где A - ID отдела(число) "); Console.WriteLine("где В - ID должности(число) "); Console.WriteLine("где С - фамилия работника(строка) "); Console.WriteLine("где D - зарплата сотрудника(число) "); Console.WriteLine("где E - % от зарплаты на премию(число) "); Console.WriteLine("где D - поправочный коэффициент(число) "); return (int)ReturnCodes.ErrorArgs; } #endregion int check = 0; //Проверяем на существование введённых номера отдела и должности check = CheckExistence(role, department); if (check != 0) { return check; } //В зависимости от количества аргументов командной строки, создаём объект Emploee switch (args.Length) { case 1: { employee = new Employee((Departments)department, (Ranks)role, strs[1]); break; } case 2: { try { employee = new Employee((Departments)department, (Ranks)role, strs[1], Int32.Parse(args[1])); } #region CatchBlock catch (FormatException e) { Console.WriteLine("Неверный формат данных у зарплаты!"); Console.WriteLine("Зарплата должна указываться числом!"); return (int)ReturnCodes.ErrorArgs; } #endregion break; } case 3: { try { employee = new Employee((Departments)department, (Ranks)role, strs[1], Int32.Parse(args[1]), Byte.Parse(args[2])); } #region CatchBlock catch (FormatException e) { Console.WriteLine("Неверный формат данных у зарплаты или у процентов бонуса!"); Console.WriteLine("Зарплата и проценты должны указываться числами!"); return (int)ReturnCodes.ErrorArgs; } #endregion break; } case 4: { try { employee = new Employee((Departments)department, (Ranks)role, strs[1], Int32.Parse(args[1]), Byte.Parse(args[2]), Double.Parse(args[3])); } #region CatchBlock catch (FormatException e) { Console.WriteLine("Неверный формат данных у зарплаты или у процентов или у коэффициента!"); Console.WriteLine("Зарплата, проценты и коэффициент должны указываться числами!"); return (int)ReturnCodes.ErrorArgs; } #endregion break; } default: { Console.WriteLine("ERROR: Не указан обязательный аргумент командной строки!"); return (int)ReturnCodes.ErrorArgs; } } try { //рассчитываем бонус работника employee.CulcBonus(); } #region CatchBlock catch (NullReferenceException exNull) { Console.WriteLine("Невозможно рассчитать бонус рабочего, т.к. входящие параметры заданы не верно!"); return (int)ReturnCodes.ErrorArgs; } #endregion //Создаём вспомагательные переменные, т.к. св-ва нельзя передавать с ref/out. decimal bonus = employee.Bonus; int TaxRate=0; //Снимается налог с бонуса bool payTax=PayTax(ref bonus, out TaxRate); employee.Bonus = bonus; //Вывод результатов на экран Console.WriteLine("Cотрудник:"+employee.LastName.ToUpper()); Console.WriteLine("Должность:"+employee.Role.ToString()); Console.WriteLine("Отдел:" + employee.Department.ToString()); Console.WriteLine("Премия:" + employee.Bonus); if (payTax == true) { Console.WriteLine("Включая налог:" + constTaxRate + "%"); } else { Console.WriteLine("Не включая налог:"+ constTaxRate + "%"); } return 0; } /// <summary> /// The method for paying taxes. /// </summary> /// <param name="bonus">The amount of bonus.</param> /// <param name="TaxRate">c</param> /// <returns>True - if tax paid, false - if tax is not paid.</returns> static bool PayTax(ref decimal bonus, out int TaxRate) { if (bonus > minBonusOfTax) { TaxRate = constTaxRate; bonus = bonus - (bonus * TaxRate / 100); return true; } else { TaxRate = 0; return false; } } /// <summary> /// The function validate id deparnments and id ranks. /// </summary> /// <param name="checkR">The id ranks.</param> /// <param name="checkD">The id deparnments.</param> /// <returns>0 - if successfully /// -2 - if id departments is not validate /// -3 - if id ranks is not validate</returns> static int CheckExistence( int checkR, int checkD) { Array arrD = Enum.GetValues(typeof(Departments)); if (checkD > (int)arrD.GetValue(0) && checkD <= (int)arrD.GetValue(arrD.Length - 1)) { Array arrR = Enum.GetValues(typeof(Ranks)); if (checkR > (int)arrR.GetValue(0) && checkR <= (int)arrR.GetValue(arrR.Length - 1)) return (int)ReturnCodes.Ok; else { Console.WriteLine("Указанной должности не существует!"); return (int)ReturnCodes.ErrorDepartments; } } else { Console.WriteLine("Указанного отдела не существует!"); return (int)ReturnCodes.ErrorRanks; } } } |
"...C суммы премии большей чем 10..."
ОтветитьУдалитьнаверное правильно так: "... С суммы большей или равной 10...", потому что ниже идет "В случае же если премия составила < 10 и налог не взимался "Не включая налог: 13%"
Не нашел в задании о том какой код должна вернуть программа, если формат аргументов неверный. Например в первом аргументе не запятая, а точка или вообще одно слово, а также если аргументы-цифры не могут быть "отпарсены". В общем, отойду немного от задания и создам еще один возвращаемый код.
ОтветитьУдалитьbonus = (decimal)((salary * percentOfSalary / 100) * correctionFactor); - есть риск, что будет переполнение при вычислении выражения "salary * percentOfSalary", int * byte -> int, если исходный int был большим, то в итоговый произведение не поместится.
ОтветитьУдалитьВот моя версия, когда делал авторскую не смотрел, только потом сравнил, где-то подход совпадал, где-то нет.
ОтветитьУдалить// Перечисление "Возвращаемые коды"
public enum ReturnCodes
{
OK = 0,
MissedArgument = -1,
CantFindDept = -2,
CantFindRank = -3,
InvalidArgument = -4
}
// Перечисление "Отделы"
public enum Departments
{
RD = 0, //Отдел разработок
QA, //Отдел тестирования
Support, //Отдел технической поддержки
Sales, //Отдел продаж
Marketing, //Отдел маркетинга
}
// Перечисление "Должности"
public enum Ranks
{
Employee = 0,
Lead,
Manager,
Director
}
// Класс "Сотрудник"
ОтветитьУдалитьpublic class Employee
{
// Свойство "Имя сотрудника"
public string Name { get; set; }
// Свойство "Должность"
public Ranks Rank { get; set; }
// Свойство "Отдел"
public Departments Department { get; set; }
// Свойство "Зарплата"
public int Salary { get; set; }
// Свойство "Процент премии"
public byte SalaryPercent { get; set; }
// Свойство "Поправочный коэффициент"
public double Coefficient { get; set; }
// Свойство "Бонус"
public decimal Bonus
{
// Значения свойства вычисляется по формуле
get
{
return decimal.Round((decimal)Salary * (decimal)SalaryPercent * (decimal)Coefficient / 100, 2);
}
// Значение свойства нельзя установить напрямую
protected set
{
}
}
// Конструктор
public Employee()
{
// Значения по умолчанию
Salary = 500;
SalaryPercent = 10;
Coefficient = 0.96;
}
// Процедура инициализации свойств объекта из массива строк
public ReturnCodes Parse(string[] args)
{
// Количество аргументов (по заданию не превышает четырех)
byte argsCount = unchecked((byte)args.Count());
// Первый аргумент обязательный
if (argsCount < 1) return ReturnCodes.MissedArgument;
// В первом аргументе должно быть не менее 4 символов (1-Отдел, 2-Должность, 3-Запятая, 4-Имя)
if (args[0].Length < 4) return ReturnCodes.InvalidArgument;
// Проверка на запятую
if (args[0].Substring(2, 1) != ",") return ReturnCodes.InvalidArgument;
// Получение отдела
int department;
if (!int.TryParse(args[0].Substring(0, 1), out department)) return ReturnCodes.InvalidArgument;
if (!Enum.IsDefined(typeof(Departments), department)) return ReturnCodes.CantFindDept;
this.Department = (Departments)department;
// Получение должности
int rank;
if (!int.TryParse(args[0].Substring(1, 1), out rank)) return ReturnCodes.InvalidArgument;
if (!Enum.IsDefined(typeof(Ranks), rank)) return ReturnCodes.CantFindRank;
this.Rank = (Ranks)rank;
// Получение имени
this.Name = args[0].Substring(3);
// Получение з/п
if (argsCount > 1)
{
int salary;
if (!int.TryParse(args[1], out salary)) return ReturnCodes.InvalidArgument;
this.Salary = salary;
}
// Получение %
if (argsCount > 2)
{
byte salaryPercent;
if (!byte.TryParse(args[2], out salaryPercent)) return ReturnCodes.InvalidArgument;
this.SalaryPercent = salaryPercent;
}
// Получение поправочного коэффициента
if (argsCount > 3)
{
double coefficient;
if (!double.TryParse(args[3], out coefficient)) return ReturnCodes.InvalidArgument;
this.Coefficient = coefficient;
}
return ReturnCodes.OK;
}
// Процедура вывода информации о сотруднике
public override string ToString()
{
return "Сотрудник: " + Name.ToUpper()
+ "\nДолжность: " + Rank
+ "\nОтдел: " + Department
+ "\nПремия: " + Bonus;
}
}
// Класс "Получатель налогов"
ОтветитьУдалитьpublic static class TaxGetter
{
// Константа "Налоговая ставка"
const int taxrate = 13;
// Константа "Порог налогообложения"
const int maxvalue = 10;
// Функция, которая снимает % налога, если премия больше или равна порогу налогообложения
public static bool PayTax(ref decimal bonus, out int TaxRate)
{
TaxRate = taxrate;
if (bonus < maxvalue) return false;
bonus = decimal.Round(bonus * (100 - taxrate)/100, 2);
return true;
}
}
// Основная программа
ОтветитьУдалитьclass Program
{
static int Main(string[] args)
{
Employee employee = new Employee();
ReturnCodes returnCode = employee.Parse(args);
if (returnCode == ReturnCodes.OK)
{
Console.WriteLine(employee);
decimal bonus = employee.Bonus;
int TaxRate = 0;
if (TaxGetter.PayTax(ref bonus, out TaxRate))
Console.WriteLine("Включая налог: 13 %");
else
Console.WriteLine("Не включая налог: 13 %");
}
else
{
Console.WriteLine("Программа завершилась с ошибкой. Код ошибки: {0}", (int)returnCode);
}
Console.ReadKey();
return (int)returnCode;
}
}