Показаны сообщения с ярлыком C#. Показать все сообщения
Показаны сообщения с ярлыком C#. Показать все сообщения

вторник, 28 июня 2011 г.

Статические конструкторы в C#



В этой статье мы поговорим о статических конструкторах в C#. Сначала немного теории. Что же такое статический конструктор и для чего он используется?

Статический конструктор нельзя вызывать напрямую. Если обычный конструктор вызывается в момент создания экземпляра класса, то статический – вызывается автоматически перед созданием первого экземпляра класса или перед использованием ссылки на какие-либо статические члены. Инициализация статических переменных в коде C# компилируется CLR в статический конструктор, различие его от конструктора, заданного в явном виде лишь в одном атрибуте MS IL, как раз и определяющего логику вызова (отложено/при обращении). 

Такой конструктор бывает полезен для выполнения каких-либо подготовительных действий, которые должны быть выполнены только один раз. В статическом конструкторе можно задать начальные значения для статических переменных класса, проинициализировать компоненты, применяемых ко всему классу, а не к отдельному экземпляру объекта этого класса. Также типичным использованием статических конструкторов является случай, когда класс использует файл журнала и конструктор применяется для добавления записей в этот файл.  Статические конструкторы бывают полезны при создании классов-оболочек для неуправляемого кода, когда конструктор может вызвать метод LoadLibrary.

Примечание: как и в отношении многих вещей в .NET Runtime, пользователь не может знать заранее, в какой момент будет вызван статический конструктор. .NET Runtime гарантирует только то, что он будет вызван где-то в промежутке между моментом запуска программы и созданием первого объекта данного класса. Это, в частности, означает, что в статическом конструкторе нельзя предполагать, что объект будет создан в самое ближайшее время.

Если статический конструктор инициирует исключение, среда выполнения не вызывает его во второй раз, и тип остается неинициализированным на время существования домена приложения, в котором выполняется программа. Ещё хотелось отметить, что статический конструктор не принимает модификаторы доступа и не имеет параметров.

Чтобы объявить статический конструктор, достаточно просто добавить модификатор static перед объявлением конструктора. Статический конструктор не может иметь параметров.
class MyClass {
   static MyClass() {
      //...
   }
}
Для деструкторов никаких статических аналогов не существует.

Теперь, когда нам известна теория, попробуем сделать задание. Рассмотрим следующий код и попробуем ответить на следующие вопросы: Что произойдет при запуске программы?
           1. Ошибка компиляции. В каком месте?
           2. Ошибка выполнения. В каком месте? Что успеет вывестись на консоль?
           3. Ошибок не будет. Что будет выведено на консоль?

using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Diagnostics;
using System.Threading;
using System.Runtime.InteropServices;

namespace Tests
{
    class Program
    {
        #region StaticConstructor&Inherit

        public interface IWritable
        {
            string Write();
        }

        public class A : IWritable
        {
            public static int intVarA;

            static A()
            {
                intVarA = C.intVarC + B.intVarB + 5;
            }

            public virtual string Write()
            {
                return "A.Write()";
            }
        }

        public class B : A, IWritable
        {
            public static int intVarB;

            static B()
            {
                intVarB = C.intVarC + A.intVarA + 5;
            }

            public override string Write()
            {
                return "B.Write()";
            }
        }

        public class C : B, IWritable
        {
            public static int intVarC;

            static C()
            {
                intVarC = B.intVarB + A.intVarA + 5;
            }

            public new string Write()
            {
                return "C.Write()";
            }
        }

        #endregion



        static void Main(string[] args)
        {

            #region StaticConstructor&Inherit

            Console.WriteLine(A.intVarA);
            Console.WriteLine(B.intVarB);
            Console.WriteLine(C.intVarC);
            Console.WriteLine();

            #endregion

            Console.ReadLine();
        }
    }
}

Ответ: На консоли будет выведено три числа: 20, 5, 10.

Почему вывод в консоли будет именно такой, давайте разберёмся. Сначала когда вызывается строчка Console.WriteLine(A.intVarA); в консоль должно вывестись значение статической переменной A.intVarA, по умолчанию переменные типа int инициализируются нулём но в классе A присутствует статический конструктор, который как мы уже знаем будет запущен до обращения к любому члену класса A.
            static A()
            {
                intVarA = C.intVarC + B.intVarB + 5;
            }

В этом конструкторе используются статические переменные C.intVarC и B.intVarB. Классы B и С также имеют статические конструкторы и мы заходим в них до инициализации статических переменных. Сначала в конструктор класса С.

            static C()
            {
                intVarC = B.intVarB + A.intVarA + 5;
            }

Тут, чтобы посчитать переменную intVarC, компилятору необходимо выполнить статический конструктор класса В.

            static B()
            {
                intVarB = C.intVarC + A.intVarA + 5;
            }

Здесь мы опять видим переменные C.intVarC и A.intVarA, похоже на зацикливание. J НО как мы помним, статический конструктор вызывается только один раз! А у  нас в программе все статические конструкторы уже были вызваны, поэтому больше вызываться статические конструкторы не будут. Вспомним чему у нас равна переменная C.intVarC= B.intVarB + A.intVarA + 5 = 0 + 0 = 5. Т.к. по умолчанию int инициализируются нулём. Аналогично можно вычислить intVarC = B.intVarB + A.intVarA + 5 = 5 + 0 + 5 = 10. Осталось вычислить intVarA = C.intVarC + B.intVarB + 5 = 10 + 5 + 5 = 20. Теперь, я надеюсь, всё понятно, почему программа вывела такие числа на консоль. Если объяснение не очень понятно, то попробуете подебажить программу по шагам и всё поймёте.

Надеюсь, статья была познавательной и интересной для вас. Следующая статья будет про наследование в C#.


Операторы checked /unchecked и цикл for в C#


В этой статье поговорим немножко о цикле for и об операторах checked /unchecked.

Циклом называется один или несколько операторов, повторяющихся заданное число раз или до тех пор, пока не будет выполнено определенное условие. Выбор типа цикла зависит от задачи программирования и личных предпочтений кодирования. 
Оператор for повторно выполняет заключенный в цикл оператор (или несколько операторов) следующим образом.
  •        Сначала вычисляется начальное значение параметра цикла.
  •          Затем, пока условие получает значение true, оператор в теле цикла выполняется и затем происходит новое вычисление параметра цикла.
  •          Когда условие получает значение false, управление передается вне цикла.

Поскольку тестирование условного выражения осуществляется до выполнения цикла, оператор for выполняется ноль или более раз. Все выражения оператора for являются необязательными.  

Рассмотрим следующий пример. Попробуйте ответить на вопросы в тексте программы.


using System.IO;
using System.Diagnostics;
using System.Threading;
using System.Runtime.InteropServices;

namespace Tests
{
    class Program
    {
        #region Вопрос

        /* Вопрос (если не указан другой):
         
            Что произойдет при запуске программы?
           1. Ошибка компиляции. В каком месте?
           2. Ошибка выполнения. В каком месте? Что успеет вывестись на консоль?
           3. Ошибок не будет. Что будет выведено на консоль?
        */

        #endregion

        static void Main(string[] args)
        {
            #region Cycle

            for (int i = int.MaxValue - 10; i <= int.MaxValue; i++)
            {
                Console.WriteLine("a");
            }

            #endregion

            Console.ReadLine();
        }
    }
}


Ответ:  Обычно человек отвечает что буква “a” выведется 10 раз на консоль, после чего выполнение программы прекратится, однако не тут то было J Результат довольно неожиданный.
Буква “a” будет выведена бесконечное количество раз, программа зациклится. Так как при выполнении цикла, когда i уже равняется максимальному значению, в цикле к i прибавляется ещё 1 и происходит переполнение.  По умолчанию неконстантные выражения не проверяются на переполнение во время выполнения, и они не создают исключений переполнения. И тогда i станет равной minValue, и цикл продолжит свою работу. 

Почему же если прибавить к maxValue один получается minValue? Опустимся на уровень байтов и посмотрим ,что же происходит. Есть, например байт 11111111 - это максимум, если к нему прибавить 1, то будет 1 0000 0000, первая 1 выходит за байт, следовательно  остается 0000 0000, а это минимальное значение.

Проверку переполнения можно включить посредством параметров компилятора, настройки среды или использования ключевого слова checked. В следующем примере демонстрируется использование выражения checked или блока checked для обнаружения переполнения, возникающего в результате увеличения i во время выполнения. 

Рассмотрим следующий пример.

using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Diagnostics;
using System.Threading;
using System.Runtime.InteropServices;

namespace Tests
{
    class Program
    {

        #region Вопрос

        /* Вопрос (если не указан другой):
         
            Что произойдет при запуске программы?
           1. Ошибка компиляции. В каком месте?
           2. Ошибка выполнения. В каком месте? Что успеет вывестись на консоль?
           3. Ошибок не будет. Что будет выведено на консоль?
        */

        #endregion

        static void Main(string[] args)
        {

            #region AnotherCycle

            checked
            {
                for (int i = int.MaxValue - 10; i <= int.MaxValue; i++)
                {
                    Console.WriteLine("a");
                }
            }

            #endregion

            Console.ReadLine();
        }
    }
}


Ответ:  На консоль выведется десять раз буква “a”  после чего возникнет исключение System.OverflowException,  где Message="Переполнение в результате выполнения арифметической операции".

Почему такое происходит. Конечно же, причина кроется в операторе checked. Что же это за оператор, рассмотрим его подробнее?


Операторы C# могут выполняться в проверяемом или непроверяемом контексте. В проверяемом контексте арифметическое переполнение вызовет исключение. В непроверяемом контексте арифметическое переполнение будет проигнорировано, а результат усечен.

·         checked   -  используется для явного включения проверки переполнения при выполнении арифметических операций и преобразований с данными целого типа. По умолчанию выражение, содержащее только константные значения, вызывает ошибку компилятора в том случае, если результат его вычисления выходит за допустимые пределы значений конечного типа. Если выражение содержит одно или несколько неконстантных значений, компилятор не выполняет проверку переполнения. 
·         unchecked   - используется для подавления проверки переполнения при выполнении арифметических операций и преобразований с данными целого типа. Если в непроверяемом контексте результатом выполнения выражения является значение, выходящее за допустимые пределы значений конечного типа, то переполнение не помечается. Вычисление в приведенном ниже примере выполняется в блоке или выражении unchecked, поэтому факт превышения результатом максимального значения целого числа игнорируется.

Если не указано ни checked, ни unchecked, контекст по умолчанию зависит от внешних факторов, например параметров компилятора.

Проверка переполнений влияет на следующие операции.

·         Выражения, использующие следующие предопределенные операторы в целых типах:
++   —   - (унарный)   +   -   *   /
·         Явные числовые преобразования между целыми типами данных.

С помощью параметра компилятора /checked можно указать проверяемый или непроверяемый контекст для всех целочисленный арифметических операторов, которые явно не выражены в области действия ключевого слова checked или unchecked.
Надеюсь вам была интересна данная статья. В следующей статье мы рассмотрим такие темы как наследование, и коснёмся темы статических конструкторов.


Разбор тестового задания на C#


На собеседование в одной из фирм мне дали вот такое тестовое задание на знание основ 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
}
Далее опишем самый главный класс Employee, в котором содержатся соответствующие свойства типа lastName, department и д.р., а также метод для вычисления бонуса CulcBonus()
/// <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;
}
}
}
Надеюсь, вам понравилось задание, интересно будет увидеть ваши реализации.