Назад Вперед Содержание


ЗАДАЧИ ДЛЯ СТУДЕНТОВ, ЗНАКОМЫХ С С#

ПРИМЕР ЗАДАЧ

Задача 1 (Классы, свойства, индексаторы. Одномерные, прямоугольные и ступенчатые массивы)

Требования к программе, общие для всех вариантов

  1. Определить класс Person, который имеет
  2. В классе Person определить конструкторы:
  3. В классе Person определить свойства c методами get и set:
  4. В классе Person определить
  5. Для этого в методе Main() создать

Тип элементов массивов зависит от варианта работы. Массивы должны иметь одинаковое число элементов. Если число строк в двумерном прямоугольном массиве равно nrow, а число столбцов ncolumn, то одномерный массив должен содержать nrow*ncolumn элементов, в двумерном ступенчатом массиве общее число элементов также должно быть равно nrow*ncolumn.

Значения nrow и ncolumn вводятся в процессе работы приложения в виде одной строки с разделителями. В приглашении, которое получает пользователь, должна быть информация о том, какие символы можно использовать как разделители, число разделителей должно быть больше 1. С помощью метода Split класса System.String приложение разбирает введенную пользователем текстовую строку с информацией о числе строк и числе столбцов двумерного массива и присваивает значения переменным, которые содержат значения nrow и ncolumn. В первой лабораторной работе не требуется обрабатывать ошибки ввода, предполагается, что пользователь правильно ввел данные. Приложение распределяет память для всех массивов и инициализирует элементы массивов. Для инициализации элементов можно использовать конструктор без параметров.

Для всех элементов массивов выполняется одна и та же операция, например, присваивается значение одному из свойств, определенных для элементов массива. В лабораторной работе требуется сравнить время выполнения этой операции для одномерного, двумерного прямоугольного и двумерного ступенчатого массивов с одинаковым числом элементов.

Для измерения времени выполнения операций можно использовать свойство Environment.TickCount. Cтатическое свойство TickCount класса Environment имеет тип int, использует информацию системного таймера и содержит время в миллисекундах, которое прошло с момента перезагрузки компьютера. Чтобы получить время выполнения некоторого блока кода, необходимо вызвать Environment.TickCount непосредственно перед блоком и сразу же после последнего оператора блока и взять разность значений.

В блоке кода, для которого измеряется время, не должно быть операций распределения памяти для массивов, инициализации элементов массивов и операций вывода данных на консоль. Блоки кода должны содержать только операции с элементами массива. Вычисленные значения времени выполнения операций для трех типов массивов, а также число строк nrow и столбцов ncolumn выводятся на консоль. Вывод должен быть подписан, т.е. вывод должен содержать информацию о том, какому типу массива отвечает выведенное значение. ?

ПРИМЕР ВАРИАНТА ЗАДАЧИ И ЕЕ РЕАЛИЗАЦИИ

Вариант задачи. Требования к программе

  1. Определить тип Education - перечисление(enum) со значениями Specialist, Вachelor, SecondEducation.
  2. Определить класс Exam, который имеет три открытых автореализуемых свойства, доступных для чтения и записи:
  3. Определить класс Student, который имеет
  4. В классе Student определить конструкторы:
  5. В классе Student определить свойства c методами get и set:
  6. В классе Student определить
  7. В методе Main()
    1. Создать один объект типа Student, преобразовать данные в текстовый вид с помощью метода ToShortString() и вывести данные.
    2. Вывести значения индексатора для значений индекса Education.Specialist, Education.Bachelor и Education.SecondEducation.
    3. Присвоить значения всем определенным в типе Student свойствам, преобразовать данные в текстовый вид с помощью метода ToString() и вывести данные.
    4. C помощью метода AddExams( params Exam[] ) добавить элементы в список экзаменов и вывести данные объекта Student, используя метод ToString().
    5. Сравнить время выполнения операций с элементами одномерного, двумерного прямоугольного и двумерного ступенчатого массивов с одинаковым числом элементов типа Exam.

Проект. Консольное приложение

Создаем проект csharptrain.Определяем тип Education - перечисление(enum) со значениями Specialist, Вachelor, SecondEducation. Добавляем перед классом programm перечисление:

enum Education
    {
        Specialist,
        Bachelor,
        SecondEducation
    }
 

Определяем класс Exam, который имеет три открытых автореализуемых свойства, доступных для чтения и записи:

     
    /// Класс, задающий объектное представление экзамена в данной программе
    
    class Exam
    {
        public string SubjectName;
        public int Mark { get; set; }
        public DateTime Date { get; set; }
        /// 
        /// Конструктор с параметрами класса Exam
        /// 
        public Exam(string SubjectName, int Mark, DateTime DateOfExam)
        {
            this.SubjectName = SubjectName;
            this.Mark = Mark;
            Date = DateOfExam;
        }
        /// 
        /// Конструктор без параметров класса Exam
        /// 
        public Exam()
        {
            SubjectName = "Computer Logic";
            Mark = 5;
            Date = new DateTime(2016, 6, 15, 12, 0, 0);
        }
        public override string ToString()
        {
            return "Exam : " + SubjectName + "\tMark: " + Mark.ToString() + "\tDate: " + Date.ToString("h:mm d-MM-yyyy");
        }
      
  }

Определяется класс Student, который имеет

  1. В классе Student определить конструкторы:
  2. В классе Student определить свойства c методами get и set:
  3. В классе Student определить
    
    /// Класс обеспечивает объектное представление свойств студента, а также простой доступ к ним.
    
    class Student : Person
    {
        public Education Education { get; set; }
        private int GroupId = -1;
        private int GroupID
        {
            get
            {
                return GroupId;
            }
            set
            {
                if (value <= 100 || value > 599)
                    throw new Exception("Incorrect group ID! Correct groupID range is [101-599]");
                GroupId = value;
            }
        }
        public Exam[] Exams; //Intentionally left public to perform faster testing
        private List Tests;
        public double AverageMark
        {
            get
            {
                return Exams.Sum((x) => x.Mark) / Exams.Length;
            }
        }
        public Person Person
        {
            get
            {
                return new Person(base.Name, base.Age, base.Date);
            }
            set
            {
                Date = value.Date;
                Age = value.Age;
                Name = value.Name;
            }
        }
        public Exam[] getExams
        {
            get
            {
                Exam[] ExamsCopy = new Exam[Exams.Length];
                Array.Copy(Exams, ExamsCopy, Exams.Length);
                return ExamsCopy;
            }
            set
            {
                Array.Copy(value, Exams, value.Length);
            }
        }
        
        
        /// Конструктор класса student с параметрами Person person,Education Education, int GroupID
       
        public Student(Person person, Education Education, int GroupID)
            : base(person)
        {
            this.Education = Education;
            this.GroupID = GroupID;
            Exams = new Exam[0];
            Tests = new List();
        }
       
        /// Конструктор класса Student без параметров

        public Student()
            : base()
        {
            Education = Education.Bachelor;
            GroupID = 101;
            Exams = new Exam[0];
            Tests = new List();
        }
        public bool this[Education Education]
        {
            get { return Education == this.Education; }
        }
  
        /// Добавляет экзамены студенту
        /// Массив экзаменов, которые нужо добавить 
        public void AddExams(Exam[] exams)
        {
            Exams = Exams.Concat(exams).ToArray();
            Exam[] tmp = new Exam[Exams.Length];
        }
       
        /// Добавляет зачеты студенту
      
        public void AddTests(Test[] tests)
        {
            Tests.AddRange(tests);
        }
        public override string ToString()
        {
            return "Student : " + Name + "\tEducation : " + Education + "\tGroupID : " + GroupID.ToString()
                + MyUtilits.Sum(Exams, (x) => { return Environment.NewLine + x.ToString(); });
        }
        public string ToShortString()
        {
            return "Student : " /*+ StudentData.ToString()*/ + "\tEducation :" + Education + "\tGroupID :" + GroupID.ToString()
                + "\tAvg. Mark : " + AverageMark.ToString();
        }
    }

Тестируем проект, для этого в методе Main()

  1. Создаем один объект типа Student,чтобы преобразовать данные в текстовый вид с помощью метода ToShortString() и выводим данные.
  2. Выводим значения индексатора для значений индекса Education.Specialist, Education.Bachelor и Education.SecondEducation.
  3. Присваиваем значения всем определенным в типе Student свойствам, преобразуем данные в текстовый вид с помощью метода ToString() и выводим данные.
  4. C помощью метода AddExams( params Exam[] ) добавляем элементы в список экзаменов и выводим данные объекта Student, используя метод ToString().
  5. Сравниваем время выполнения операций с элементами одномерного, двумерного прямоугольного и двумерного ступенчатого массивов с одинаковым числом элементов типа Exam.

Класс Test, задающий представление зачета в этой программе


    /// Класс, задающий представление зачета в этой программе
  
    class Test
    {
        public string SubjectName;
        public bool Closed { get; set; }
        public Test(bool Closed = true, string SubjectName = "Maths")
        {
            this.Closed = Closed;
            this.SubjectName = SubjectName;
        }
        public override string ToString()
        {
            return SubjectName + " : " + Closed.ToString();
        }
    }

    static void Main(string[] args)
        {
            Person p1 = new Person("Valeriy", 18, new DateTime(1998, 3, 3));
            Person p2 = new Person("Valeriy", 18, new DateTime(1998, 3, 3));
            System.Console.Out.WriteLine(object.ReferenceEquals(p1, p2).ToString() + " " + p1.Equals(p2).ToString());

            Student student = new Student(p1, Education.Bachelor, 101);
            Exam[] exams = new Exam[4];
            exams[0] = new Exam("Linear Math", 5, new DateTime(2016, 12, 23, 12, 0, 0));
            exams[1] = new Exam("Algorithms", 5, new DateTime(2016, 11, 23, 12, 0, 0));
            exams[2] = new Exam("Math Analysis", 3, new DateTime(2016, 10, 23, 12, 0, 0));
            exams[3] = new Exam("Discrete Maths", 4, new DateTime(2016, 10, 23, 12, 0, 0));
            student.AddExams(exams);
            Test[] tests = new Test[4];
            tests[0] = new Test(true, "Computer logics");
            tests[1] = new Test(true, "Linear Maths");
            tests[2] = new Test(false, "Math Analysis");
            tests[3] = new Test(true, "Discrete Maths");
            student.AddTests(tests);

            System.Console.Out.WriteLine(student.Person);
            System.Console.Out.WriteLine(student.ToString());
          
        }

Результат .

Задача 2.Наследование. Исключения. Интерфейсы. Итераторы и блоки итераторов

Информация для всех вариантов

  1. В классе Person из задачи 1 и в классах, дополнительно указанных в вариантах, надо
  2. Реализация виртуального метода bool Equals (object obj) в классе System.Object определяет равенство объектов как равенство ссылок на объекты. Некоторые классы из базовой библиотеки BCL переопределяют метод Equals(). В классе System.String этот метод переопределен так, что равными считаются строки, которые совпадают посимвольно. Реализация метода Equals() в структурном типе DateTime равенство объектов DateTime определяет как равенство значений.
  3. В задаче требуется переопределить метод Equals так, чтобы объекты считались равными, если равны все данные объектов. Для класса Person это означает, что равны даты рождения и посимвольно совпадают строки с именем и фамилией.
  4. Определение операций == и != должно быть согласовано с переопределенным методом Equals, т.е. критерии, по которым проверяется равенство объектов в методе Equals, должны использоваться и при проверке равенства объектов в операциях == и !=.

    Переопределение виртуального метода int GetHashCode() также должно быть согласовано с операциями == и !=. Виртуальный метод GetHashCode() используется некоторыми классами базовой библиотеки, например, коллекциями-словарями. Классы базовой библиотеки, вызывающие метод GetHashCode() из пользовательского типа, предполагают, что равным объектам отвечают равные значения хэш-кодов. Поэтому в случае, когда под равенством объектов понимается совпадение данных (а не ссылок), реализация метода GetHashCode() должна для объектов с совпадающими данными возвращать равные значения хэш-кодов.

  5. В классах, указанных в вариантах работы, требуется определить метод object DeepCopy() для создания полной копии объекта. Определенные в некоторых классах базовой библиотеки методы Clone() и Copy() создают ограниченную (shallow) копию объекта – при копировании объекта копии создаются только для полей структурных типов, для полей ссылочных типов копируются только ссылки. В результате в ограниченной копии объекта поля-ссылки указывают на те же объекты, что и в исходном объекте. Метод DeepCopy() должен создать полные копии всех объектов, ссылки на которые содержат поля типа. После создания полная копия не зависит от исходного объекта - изменение любого поля или свойства исходного объекта не должно приводить к изменению копии. При реализации метода DeepCopy() в классе, который имеет поле типа System.Collections.ArrayList, следует иметь в виду, что определенные в классе ArrayList конструктор ArrayList(ICollection) и метод Clone() при создании копии коллекции, состоящей из элементов ссылочных типов, копируют только ссылки.
  6. Метод DeepCopy() должен создать как копии элементов коллекции ArrayList, так и полные копии объектов, на которые ссылаются элементы коллекции. Для типов, содержащих коллекции, реализация метода DeepCopy() упрощается, если в типах элементов коллекций также определить метод DeepCopy().

Задача 3. Делегаты. События

Информация для всех вариантов

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

Коллекция состоит из объектов ссылочных типов. Коллекция изменяется при удалении/добавлении элементов или при изменении одной из входящих в коллекцию ссылок, например, когда одной из ссылок присваивается новое значение. В этом случае в соответствующих методах или свойствах класса бросаются события.

При изменении данных объектов, ссылки на которые входят в коллекцию, значения самих ссылок не изменяются. Этот тип изменений не порождает событий.

Для событий, извещающих об изменениях в коллекции, определяется свой делегат. События регистрируются в специальных классах-слушателях.

Вариант задачи.

Требования к программе

  1. Определить класс StudentCollection, которая с помощью событий сообщает об изменениях в коллекции.
  2. Для событий определить делегат StudentListHandler с сигнатурой:

    void StudentListHandler (object source, StudentListHandlerEventArgs args);

  3. Класс StudentListHandlerEventArgs, производный от класса System.EventArgs, содержит
  4. В новую версию класса StudentCollection добавить
  5. В новую версию класса StudentCollection добавить два события типа StudentListHandler

Пример реализации проекта (все три задачи)

Создается интерфейс для классов, которые содержат дату и метод полного копирования, причем все дочерние объекты нового класса не являлись бы ссылками на дочерние объекты копируемого класса.

В теме 5 (а именно в 5.7) рассматривались два стандартных интерфейса, сейчас рассмотрим ещё два IEnumerable,IEnumerator. Наверняка было бы достаточно удобно обращаться к внутренним объектам, используя конструкцию foreach. Однако при попытке откомпилировать такую программу возникнет ошибка компиляции, которая скажет, что не реализован метод GetEnumerator интерфейса IEnumerable, который находится в пространстве имен System.Collections. Для её решения придется классы отнаследовать от интерфейса IEnumerable(используется для прохода по коллекции) и создать тело для требуемого метода.

После этого foreach уже будет компилироваться, но для того чтобы проход по объектам классов состоялся нужно реализовать методы интерфейса IEnumerator, которые неявно будут вызываться при выполнении foreach.В интерфейсе IEnumerator всего 2 метода и 1 свойство.

Методы

bool MoveNext();// переход на следующий элемент коллекции

void Reset();// переход на начало коллекции.

Под коллекцией подразумевается набор элементов какого - типа

Свойство

object Current {get;} // возвращает значение текущего элемента коллекции

Наш класс - контейнер обязан реализовать указанные выше методы и свойства.

Использование ключевого слова yield в C#

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

В одиночном лямбда-выражении часть, находящаяся справа от оператора =>, воздействует на параметр (или ряд параметров), указываемый слева. Возвращаемым результатом вычисления такого выражения является результат выполнения лямбда-оператора. Ниже приведена общая форма одиночного лямбда-выражения, принимающего единственный параметр:

параметр => выражение

Если же требуется указать несколько параметров, то используется следующая форма:

(список_параметров) => выражение

Таким образом, когда требуется указать два параметра или более, их следует заключить в скобки. Если же выражение не требует параметров, то следует использовать пустые скобки.

Лямбда-выражение применяется в два этапа. Сначала объявляется тип делегата, совместимый с лямбда-выражением, а затем экземпляр делегата, которому присваивается лямбда-выражение. После этого лямбда-выражение вычисляется при обращении к экземпляру делегата. Результатом его вычисления становится возвращаемое значение (В учебнике см.тема 3-делегаты,события, лямбды. Конкрктно об анонимных методах и лямбда-выражениях в 3.16).

Рассмотрим пример:

using System;

namespace ConsoleApplication1
{
    // Создадим несколько делегатов имитирующих 
    // простейшую форму регистрации
    delegate int LengthLogin(string s);
    delegate bool BoolPassword(string s1, string s2);

    class Program
    {
        private static void SetLogin()
        {
            Console.Write("Введите логин: ");
            string login = Console.ReadLine();

            // Используем лямбда-выражение
            LengthLogin lengthLoginDelegate = s => s.Length;

            int lengthLogin = lengthLoginDelegate(login);
            if (lengthLogin > 25)
            {
                Console.WriteLine("Слишком длинное имя\n");

                // Рекурсия на этот же метод, чтобы ввести заново логин
                SetLogin();
            }
        }

        static void Main()
        {
            SetLogin();

            Console.Write("Введите пароль: ");
            string password1 = Console.ReadLine();
            Console.Write("Повторите пароль: ");
            string password2 = Console.ReadLine();

            // Используем лямбда выражение
            BoolPassword bp = (s1, s2) => s1 == s2;

            if (bp(password1, password2))
                Console.WriteLine("Регистрация удалась!");
            else
                Console.WriteLine("Регистрация провалилась. Пароли не совпадают");

            Console.ReadLine();
        }
    }
}


Продолжим наш проект:

Результат .

Вам предлагается создать Windows Forms приложение, разместить на форме свою фотографию, вариант, фамилию и результаты работы всех трех задач.

Один из вариантов пользовательского интерфейса:

ЗАДАЧИ

  1. ЗАДАЧИ (Создать WF - приложение)
  2. ВОПРОСЫ

Назад Вперед Литература