Лабораторная работа №13
Тема: Использование интерфейсов и делегатов.
Цель: освоение составления и тестирования алгоритмов и объектно-ориентированных программ, использующих стандартные интерфейсы и делегаты.
Теоретические положения
Интерфейсы
Использование интерфейсов – удобный способ разделения функциональных возможностей. Сначала определяются интерфейсы, а затем разрабатываются классы, реализующие данные интерфейсы. Методы класса могут быть сгруппированы в разных интерфейсах.
Основной задачей интерфейса является определение контракта, не зависящего от реализации. Каждый интерфейс имеет набор методов, не реализованных непосредственно. Для каждого метода определена сигнатура, описывающая количество и тип аргументов, а также тип возвращаемого методом значения.
Пример интерфейса, описывающего методы для масштабирования объекта.
interface IScalable{ void ScaleX(double sx); void ScaleY(double sy);}Интерфейсы могут быть объявлены с любым из четырех модификаторов доступа, описанных ранее (при условии их вложенности в другие элементы), но все элементы интерфейсов должны быть общедоступны (по умолчанию).
Интерфейсы могут быть членами пространств имен, классов или структур, и могут содержать описания следующих элементов:
- Методов
- Свойств
- Индексаторов
- Событий
Интерфейсы и наследование
Вам уже известно, что в языке C# разрешено только простое наследование (наследуется только оди класс). В случае с интерфейсами разрешено и простое и множественное наследование.
interface IA{ void f();}interface IB{ void g();}class C : IA, IB{ // обязательная реализация функций f и g public void f() { ... } public void g() { ... }}
Стандартные интерфейсы .NET
В библиотеке классов .NET определено множество стандартных интерфейсов, задающих желаемое поведение объектов. Например, интерфейс IComparable задает метод сравнения объектов на «больше-меньше», что позволяет выполнять их сортировку.
Реализация интерфейсов IEnumerable и IEnumerator дает возможность просматривать содержимое объекта с помощью foreach, а реализация интерфейса ICloneable – клонировать объекты.
Стандартные интерфейсы поддерживаются многими стандартными классами библиотеки. Например, работа с массивами с помощью foreach возможна оттого что тип Array реализует интерфейсы IEnumerable и IEnumerator.
Можно создавать и собственные классы, поддерживающие стандартные интерфейсы, что позволит использовать объекты этих классов стандартными способами.
Делегаты
Делегат – это так называемый “безопасный указатель на функцию” (рис. 1). Однако, в отличие от обычных указателей на функцию в С++, делегаты C# могут вызывать более одной функции (при совместном комбинировании двух делегатов результатом будет делегат, который вызывает их обоих). Безопасность заключается в том, что делегат позволяет проверять количество передаваемых параметров, возвращаемое значение и т.д.
Рисунок 1. Делегат может ссылаться на несколько методов или функций
Делегат – это класс отнаследованный от базового класса System.MulticastDelegate. Делегаты являются ссылками на методы, инкапсулирующими настоящие указатели и предоставляющими удобные сервисы для работы с ними. Ссылки представляют собой объекты соответствующего типа.
Делегат можно объявлять как в классе, так и просто в пространстве имен. Рассмотрим синтаксис объявления делегата:
спецификатор_доступа delegate тип_возвр_значения_для_метода Имя_Делегата(список_параметров_метода)Небольшие комментарии к приведенному выше:
- спецификатор_доступа - например, public и т.д.
- delegate говорит о том что, объявляется делегат
- тип_возвр_значения_для_метода, список_параметров_метода - определяет, на что может указывать делегат. Например:
public delegate void SetFire()Делегат может указывать как на обычный метод так и на статический. Настало волшебное время - мы применим полученную о делегатах информацию во благо обществу, т.е.
Рассмотрим практический пример с использованием Делегатов:
using System;using System.Collections;class Human{ // Делегат на функцию, которая ничего не возвращает и принимает объект h public delegate void HumanDelegate(Human h); // Перечисление public enum Sex{Male,Female}; private Sex p; private string name; private string surname; private int age; // конструктор public Human(){ name = surname = "Нет Данных"; age = 0; p = Sex.Male; } // конструктор с параметрами public Human(string name,string surname,int age,Sex p){ this.name = name; this.surname = surname; this.age = age; this.p = p; } // Задание имени, возврат его public string Name{ get{ return name; } set{ name = value; } } // Задание фамилии, возврат её public string Surname{ get{ return name; } set{ name = value; } } // Задание возраста, возврат его public int Age{ get{ return age; } set{ age = value; } } // Задание пола,возврат его public Sex RealSex{ get{ return p; } set{ p = value; } } }//Класс, содержащий людейclass Firm{ ArrayList people = new ArrayList(); public Firm(){ // Добавляем в список 3 - х людей people.Add(new Human()); people.Add(new Human("Вася","Иванов",80,Human.Sex.Male)); people.Add(new Human("Катерина","Маркова",25,Human.Sex.Female)); } // Метод, принимающий делегат, четко указывается название класса, //где содержится делегат, а также название делегата public void AnalyzePeople(Human.HumanDelegate ptr){ Console.WriteLine("Будем выполнять действия над человеком !!!"); // Вызываются методы, на которые указывает делегат foreach(Human obj in people) ptr(obj); }} class Sample{ // Проверка пола static void AnalyzeSex(Human h){ if(h.RealSex==Human.Sex.Male){ Console.WriteLine("Мужчина"); } else{ Console.WriteLine("Женщина"); } } // Проверка по возрасту static void AnalyzeAge(Human h){ if(h.Age>65){ Console.WriteLine("Больше 65 лет"); } else{ Console.WriteLine("Меньше или равно 65 лет"); } } static void Main() { Console.WriteLine("Пример работы Делегата"); Firm firm = new Firm(); // В этой строке происходит использование делегатов. // Создаётся объект делегата используя ключевое слово new. // Сейчас делегат указывает на метод AnalyzeSex firm.AnalyzePeople(new Human.HumanDelegate(AnalyzeSex)); // Сейчас делегат указывает на метод AnalyzeAge firm.AnalyzePeople(new Human.HumanDelegate(AnalyzeAge)); Console.Read(); }}Вывод:
Пример работы ДелегатаБудем выполнять действия над человеком !!!МужчинаМужчинаЖенщинаБудем выполнять действия над человеком !!!Меньше или равно 65 летБольше 65 летМеньше или равно 65 летЗдесь делегат вложен в класс и поэтому для доступа к нему мы используем имя класса:
firm.AnalyzePeople(new Human.HumanDelegate(AnalyzeAge));Как уже было сказано выше делегат это класс отнаследованный от System.MulticastDelegate. Рассмотрим 2 полезных метода этого базового класса.
Первый метод Combine. Этот статический метод используется для создания делегата, указывающего на несколько разных функций (также можно пользоваться перегруженным оператором +).
Второй метод Remove. Этот статический метод удаляет делегат из списка указателей на функции. Если делегат указывает на несколько методов, то тогда при вызове делегата будут вызываться методы, на которые указывает делегат. Например (те же самые классы, но другой метод Main):
static void Main(){ Console.WriteLine("Пример работы Делегата"); Firm firm = new Firm(); // Создание делегатов Human.HumanDelegate sex = new Human.HumanDelegate(AnalyzeSex); Human.HumanDelegate age = new Human.HumanDelegate(AnalyzeAge); // Многоадресный Делегат (формируем его через +) // Произойдет вызов методов AnalyzeSex и AnalyzeAge firm.AnalyzePeople(sex+age); Console.WriteLine("\n\n"); // Многоадресный Делегат (формируем его через +) // Произойдет вызов методов AnalyzeSex и AnalyzeAge firm.AnalyzePeople(age+sex); // Или так тоже Многоадресный Делегат Console.WriteLine("\n\n"); // Многоадресный Делегат (формируем его через Combine) // Произойдет вызов методов AnalyzeSex и AnalyzeAge firm.AnalyzePeople((Human.HumanDelegate)Delegate.Combine(sex,age)); // Или так тоже можно MulticastDelegate del = age+sex; firm.AnalyzePeople((Human.HumanDelegate)del); // Удаляем один делегат Delegate onlysex = MulticastDelegate.Remove(del,age); Console.WriteLine("\n\n************************************\n\n"); // Уже не многоадресный делегат firm.AnalyzePeople((Human.HumanDelegate)onlysex); Console.Read();}Здесь через делегат вызываются статические методы класса, но это можно делать и с обычными методами. Для этого надо несколько видоизменить создание делегата. Например:
Firm firm = new Firm();// Test - это какой-то класс в нем есть методы AnalyzeSex,// AnalyzeAge Test test = new Test();//firm.AnalyzePeople(new Human.HumanDelegate(test.AnalyzeSex));firm.AnalyzePeople(new Human.HumanDelegate(test.AnalyzeAge));
Попытка вызвать делегат, в списке которого нет ни одного метода, вызывает генерацию исключения System.NullReferenceException. Поэтому при работе с делегатами уместно выполнять обработку данного исключения.
Задание
1. На примере одного из классов-потомков (выбрать самостоятельно из классов, реализованных при выполнении лабораторной работы №12) реализовать интерфейсы ICloneable, IComparable и IComparer. Реализовать поверхностное и глубокое копирование объектов, вывод отсортированного списка объектов класса по произвольному полю.
2. С помощью делегатов создать метод сортировки заданным методом списка объектов класса-коллекции. Обеспечить возможность проведения сортировки объектов по полям разных типов данных. Делегат должен передавать информацию о функции сравнения двух объектов класса-коллекции.
3. С помощью Лямбда-выражений реализовать операции поиска данных по нескольким заданным критериям и вывод найденных записей на консоль.
4. Протестировать модульными тестами работу делегатов и обработку контролируемых исключений.
Содержание отчета
1. Титульный лист.
2. Цель работы, индивидуальное задание к лабораторной работе №12.
3. Листинг программы.
4. Результаты тестирования всех методов, в том числе с применением Лямбда-выражений и в условиях возникновения исключительных ситуаций.
5. Описание различий в работе методов клонирования объектов.
6. Результаты модульного тестирования в Test Explorer.
7. Выводы.
Контрольные вопросы
1. Опишите особенности интерфейса и сравните его абстрактным классом.
2. Приведите пример реализация интерфейсов.
3. Приведите пример реализации доступа через интерфейсные ссылки.
4. Приведите пример частичных реализаций.
5. Приведите пример переменных в интерфейсах.
6. Приведите пример расширения интерфейсов.
7. Что такое делегат?
8. Как организуется вызов методов посредством делегатов?
9. Какие исключения могут быть выброшены при работе с делегатами?
10. Что такое Лямбда-выражения и для чего они применяются?
Дата добавления: 2021-12-14; просмотров: 602;