Классификация, типы интерфейсов и делегатов, их функциональные особенности и значение. Встроенные типы данных и их анализ. Интерфейсы в C#, их синтаксис и реализация, особенности использования ссылок. Условия применения делегатов вместо интерфейсов.
Аннотация к работе
Ранее мы изучали делегаты, интерфейсы, массивы, а так же подробно рассмотрели, что типы данных отличаются друг от друга и используются в той или иной ситуации. Данную курсовую работу я хочу посвятить изучения того, как можно делегаты и интерфейсы использовать в одной программе, которая выполняет определенную задачу поиска в массивах. Своей целью я поставила подробнее остановиться на ранее изученных темах, таких как интерфейсы, делегаты, массивы и общие типы. Общие (или параметризованные) типы (generics) позволяют при описании классов, структур, методов и интерфейсов использовать параметризованные параметры (не указывать тип параметра в момент написания кода). В мире.NET «тип» представляет собой просто общий термин, который применяется для обозначения любого элемента из множества (класс, интерфейс, структура, перечисление, делегат).В ходе изучения данной темы моей целью было рассмотреть, как используются общие типы при описании интерфейсов и делегатов, и рассмотреть это на примерах задач поиска в массивах.
Введение
Данная курсовая работа описывает использование общих типов при описании интерфейсов и делегатов в C# на примерах задач поиска в массивах.
Ранее мы изучали делегаты, интерфейсы, массивы, а так же подробно рассмотрели, что типы данных отличаются друг от друга и используются в той или иной ситуации.
Данную курсовую работу я хочу посвятить изучения того, как можно делегаты и интерфейсы использовать в одной программе, которая выполняет определенную задачу поиска в массивах.
Своей целью я поставила подробнее остановиться на ранее изученных темах, таких как интерфейсы, делегаты, массивы и общие типы. А затем, после подробного выяснения всех практических моментов, рассмотреть примеры программ, которые содержат в себе описания делегатов и интерфейсов, и выполняют определенный поиск в массиве.
1. Общие типы (GENERICS) интерфейс ссылка делегат
Общие (или параметризованные) типы (generics) позволяют при описании классов, структур, методов и интерфейсов использовать параметризованные параметры (не указывать тип параметра в момент написания кода). Тип параметра определяется в момент объявления переменной соответствующего типа. Таким образом можно создать некоторый общий элемент, тип который можно использовать в дальнейшем для данных различных типов.
В каждой конкретной сборке может содержаться любое количество различающихся типов. В мире.NET «тип» представляет собой просто общий термин, который применяется для обозначения любого элемента из множества (класс, интерфейс, структура, перечисление, делегат). При построении решений с помощью любого языка.NET, скорее всего, придется взаимодействовать со многими из этих типов. Например, в сборке может содержаться один класс, реализующий определенное количество интерфейсов, метод одного из которых может принимать в качестве входного параметра перечисление, а возвращать структуру.
CTS (общая система типов) представляет собой формальную спецификацию, в которой описано то, как должны быть определены типы для того, чтобы они могли обслуживаться в CLR-среде. Внутренние детали CTS обычно интересуют только тех, кто занимается разработкой инструментов и / или компиляторов для платформы.NET. Т.е. CTS описывает не просто примитивные типы данных, а целую развитую иерархию типов, включающую хорошо определенные точки, в которых код может определять свои собственные типы. Иерархическая структура общей системы типов (CTS) отражает объектно-ориентированную методологию одиночного наследования IL.
2. Типы интерфейсов
Интерфейсы представляют собой не более чем просто именованную коллекцию определений абстрактных членов, которые могут поддерживаться (т.е. реализоваться) в данном классе или структуре. В C# типы интерфейсов определяются с помощью ключевого слова interface, как показано ниже: // Объявление интерфейса public interface ICOMMANDSOURCE
{void COMMANDPARAMETER();}
Сами по себе интерфейсы мало чем полезны. Однако когда они реализуются в классах или структурах уникальным образом, они позволяют получать доступ к дополнительным функциональным возможностям за счет добавления просто ссылки на них в полиморфной форме.
3. Типы делегатов
Делегаты (delegate) являются.NET-эквивалентом безопасных в отношении типов указателей функций в стиле С. Главное отличие заключается в том, что делегат в.NET представляет собой класс, который наследуется от System. MULTICASTDELEGATE, а не просто указатель на какой-то конкретный адрес в памяти. В C# делегаты объявляются с помощью ключевого слова delegate.
Делегаты очень удобны, когда требуется обеспечить одну сущность возможностью перенаправлять вызов другой сущности и образовывать основу для архитектуры обработки событий.NET. Делегаты обладают внутренней поддержкой для групповой адресации (т.е. пересылки запроса сразу множеству получателей) и асинхронного вызова методов (т.е. вызова методов во вторичном потоке).
4. Встроенные типы данных
И, наконец, последним, что следует знать о спецификации CTS, является то, что в ней содержится четко определенный набор фундаментальных типов данных. Хотя в каждом отдельно взятом языке для объявления того или иного встроенного типа данных из CTS обычно предусмотрено свое уникальное ключевое слово, все эти ключевые слова в конечном итоге соответствуют одному и тому же типу в сборке mscorlib.dll.
В следующей таблице показано, как ключевые типы данных из CTS представляются в C#: Классы типов данных C#
Типы данных в CTS Ключевое слово в C#
System. Byte byte
System.SBYTE sbyte
System. Int16 short
System. Int32 int
System. Int64 long
System.UINT16 ushort
System.UINT32 uint
System.UINT64 ulong
System. Single float
System. Double double
System. Object object
System. Char char
System. String String
System. Boolean bool
5. Преимущества использования общих типов
I. Наиболее очевидное - повторное использование кода. Нет необходимости создавать два идентичных класса, отличающихся только типами параметров, достаточно создать один с параметризованными типами. При этом использование параметризованных типов позволяет создавать единый программный код для работы с различными типами данных. Например, единожды написанный алгоритм может работать и с целыми числами и с числами с плавающей десятичной точкой, при этом не производя на каждом шаге проверку / приведение типа. Так Generics вытесняют классы объявленные с использованием типа object.
II. Повышение производительности кода по сравнению с использование параметров типа object - нет необходимости выполнять приведение, как уже сказано выше, на каждом шаге, за счет чего получается выигрыш в производительности.
III. Проверка типов в момент компиляции программы. Поскольку не используются параметры типа object, то компилятор может выполнить проверку типа каждого параметра в момент компиляции, поскольку типы для Generic классов жестко задаются в момент объявления переменных классов этого типа.
6. Интерфейсы в C#
Синтаксис интерфейса
Интерфейс является специальным видом классов. В нем задается набор абстрактных методов, свойств и индексаторов, которые должны быть реализованы в производных классах. Иными словами, интерфейс определяет поведение, которое поддерживается реализующими этот интерфейс классами. Основная идея использования интерфейса состоит в том, чтобы к объектам таких классов можно было обращаться одинаковым образом.
Каждый класс может определять элементы интерфейса по-своему.
Так достигается полиморфизм: объекты разных классов по-разному реагируют на вызовы одного и того же метода. Синтаксис интерфейса аналогичен синтаксису класса: [атрибуты] [спецификаторы] interface
[:предки] [;]
Для интерфейса могут быть указаны спецификаторы, new, public, protected, internal и private. Спецификатор new применяется для вложенных интерфейсов и имеет такой же смысл, как и соответствующий модификатор метода класса. Остальные спецификаторы управляют видимостью интерфейса. По умолчанию интерфейс доступен только из сборки, в которой он описан (internal). Интерфейс может наследовать свойства нескольких интерфейсов, в этом случае предки перечисляются через запятую. Тело интерфейса составляют абстрактные методы, шаблоны свойств и индексаторов, а также события.
Интерфейс не может содержать константы, поля, операции, конструкторы, деструкторы, типы и любые статические элементы. В интерфейсе методы неявно являются открытыми (public-методами), при этом не разрешается явным образом указывать спецификатор доступа.
В интерфейсе имеет смысл задавать заголовки тех методов и свойств, которые будут по-разному реализованы различными классами разных иерархий. Интерфейсы же чаще используются для задания общих свойств объектов различных иерархий. Отличия интерфейса от абстрактного класса: • элементы интерфейса по умолчанию имеют спецификатор доступа public и не могут иметь спецификаторов, заданных явным образом;
• интерфейс не может содержать полей и обычных методов - все элементы интерфейса должны быть абстрактными;
• класс может иметь в списке предков несколько интерфейсов, при этом он должен определять все их методы.
Реализация интерфейса
Чтобы реализовать интерфейс, нужно указать его имя после имени класса. В списке предков класса сначала указывается его базовый класс, если он есть, а затем через запятую - интерфейсы, которые реализует этот класс. Таким образом, в С# поддерживается одиночное наследование для классов и множественное - для интерфейсов. Это позволяет придать производному классу свойства нескольких базовых интерфейсов, реализуя их по своему усмотрению.
Формат записи класса, который реализует интерфейс, таков: class : {
// тело класса
}
Методы, которые реализуют интерфейс, должны быть объявлены открытыми. Кроме того, сигнатура типа в реализации метода должна в точности совпадать с сигнатурой типа, заданной в определении интерфейса. В классах, которые реализуют интерфейсы, можно определять дополнительные члены.
Использование интерфейсных ссылок
Можно объявить ссылочную переменную интерфейсного типа. Такая переменная может ссылаться на любой объект, который реализует ее интерфейс. При вызове метода для объекта посредством интерфейсной ссылки будет выполнена та версия указанного метода, которая реализована этим объектом. Этот процесс аналогичен использованию ссылки на базовый класс для доступа к объекту производного класса.
Явная реализация интерфейса
При реализации члена интерфейса можно квалифицировать его имя с использованием имени интерфейса. В этом случае говорят, что член интерфейса реализуется явным образом, или имеет место его явная реализация.
Имя интерфейса явно указывается перед реализуемым элементом через точку. Спецификаторы доступа при этом не указываются. К таким элементам можно обращаться в программе только через объект типа интерфейса.
Закрытая реализация
Реализуя метод с использованием полностью квалифицированного имени, мы обозначаем части закрытой реализации, которые недоступны вне класса, т.е. при явном задании имени реализуемого интерфейса соответствующий метод не входит в интерфейс класса. Это позволяет упростить код программы в том случае, если какие-то элементы интерфейса не требуются конечному пользователю класса.
7. Делегаты в C#
Делегат - это вид класса, предназначенный для хранения ссылок на методы. Делегат, как и любой другой класс, можно передать в качестве параметра, а затем вызвать инкапсулированный в нем метод. Делегаты используются для поддержки событий, а также как самостоятельная конструкция языка. Рассмотрим сначала второй случай.
Описание делегатов
Описание делегата задает сигнатуру методов, которые могут быть вызваны с его помощью: [атрибуты] [спецификаторы] delegate ([параметры])
Спецификаторы делегата имеют тот же смысл, что и для класса, причем допускаются только спецификаторы new, public, protected, internal и private. Тип описывает возвращаемое значение методов, вызываемых с помощью делегата, а необязательными параметрами делегата являются параметры этих методов. Делегат может хранить ссылки на несколько методов и вызывать их поочередно, естественно, что сигнатуры всех методов должны совпадать.
Пример описания делегата: public delegate void Dd (int i);
Здесь описан тип делегата, который может хранить ссылки на методы, возвращающие void и принимающие один параметр целого типа.
Делегат, как и всякий класс, представляет собой тип данных. Его базовым классом является класс System. Delegate. Наследовать от делегата нельзя.
Объявление делегата можно размещать непосредственно в пространстве имен или внутри класса.
Использование делегатов
Для того чтобы воспользоваться делегатом, необходимо создать его экземпляр и задать имена методов, на которые он будет ссылаться. При вызове экземпляра делегата вызываются все заданные в нем методы.
Делегаты применяются в основном для следующих целей: · получения возможности определять вызываемый метод не при компиляции, а динамически во время выполнения программы;
· обеспечения связи между объектами по типу «источник - наблюдатель»;
· создания универсальных методов, в которые можно передавать другие методы;
· поддержки механизма обратных вызовов.
Использование делегата имеет тот же синтаксис, что и вызов метода. Если делегат хранит ссылки на несколько методов, они вызываются последовательно в том порядке, в котором были добавлены в делегат.
Добавление метода в список выполняется либо с помощью метода Combine, унаследованного от класса System. Delegate, либо, что удобнее, с помощью перегруженной операции сложения.
При вызове последовательности методов с помощью делегата необходимо учитывать следующее: · сигнатура методов должна в точности соответствовать делегату;
· методы могут быть как статическими, так и обычными методами класса;
· каждому методу в списке передается один и тот же набор параметров;
· если параметр передается по ссылке, изменения параметра в одном методе отразятся на его значении при вызове следующего метода;
· если параметр передается с ключевым словом out или метод возвращает значение. Результатом выполнения делегата является значение, сформированное последним из методов списка (в связи с этим рекомендуется формировать списки только из делегатов, имеющих возвращаемое значение типа voi d);
· если в процессе работы метода возникло исключение, не обработанное в том же методе, последующие методы в списке не выполняются, а происходит поиск обработчиков в объемлющих делегат блоках;
· попытка вызвать делегат, в списке которого нет ни одного метода, вызывает генерацию исключения System. Null Ref ERENCEEXCEPTI on.
8. Массивы
Массив относится к ссылочным типам данных, то есть располагается в динамической области памяти, поэтому создание массива начинается с выделения памяти под его элементы. Элементами массива могут быть величины как значимых, так и ссылочных типов (в том числе массивы). Массив значимых типов хранит значения, массив ссылочных типов - ссылки на элементы. Всем элементам при создании массива присваиваются значения по умолчанию: нули для значимых типов и null - для ссылочных.
Все массивы в С# имеют общий базовый класс Array, определенный в пространстве имен System. В нем есть несколько полезных методов, упрощающих работу с массивами, например методы получения размерности, сортировки и поиска.
Массивы, являющиеся полями класса, могут иметь те же спецификаторы, что и поля, представляющие собой простые переменные.
Одномерные массивы используются в программах чаще всего. Варианты описания массива: тип[] имя;
тип[] имя = new тип [размерность];
тип[] имя = {список инициализаторов};
тип[] имя = new тип [размерность] {список инициализаторов};
Так же используются не редко многомерные (прямоугольные) массивы. Варианты их описания могут быть следующими: тип[,] имя;
тип[,] имя = new тип [разм1, разм2];
тип[,] имя = {список инициализаторов};
тип[,] имя = new тип [разм1, разм2] {список инициализаторов};
9. Использование делегатов вместо интерфейсов
И делегаты, и интерфейсы позволяют конструктору классов отделять объявление типов от реализации. Определенный интерфейс может быть унаследован и реализован любым классом или структурой. Делегат может быть создан для метода в любом классе, если метод соответствует сигнатуре метода для делегата. Ссылка на интерфейс или делегат могут быть использованы объектом, не имеющим данных о классе, реализующем интерфейс или метод делегата. Учитывая эти сходные признаки, когда в конструкторе классов следует использовать делегат, а когда следует использовать интерфейс?
Делегат следует использовать в следующих ситуациях: · Используется шаблон разработки событий.
· Желательно инкапсулировать статический метод.
· Вызывающему не требуется доступ к другим свойствам, методам или интерфейсам объекта для реализации метода.
· Желательно простое построение.
· Классу может потребоваться несколько реализаций метода.
Интерфейс следует использовать в следующих ситуациях: · Существует группа связанных методов, которые могут быть вызваны.
· Классу потребуется только одна реализация метода.
· Класс, использующий интерфейс, будет передавать этот интерфейс другим типам классов и интерфейсов.
· Реализуемый метод связан с типом или идентификатором класса: например, методы сравнения.
Хорошим примером использования интерфейса с одним методом вместо делегата является ICOMPARABLE или более общая версия ICOMPARABLE)>). В ICOMPARABLE объявляется метод COMPARETO, возвращающий целое число, указывающее отношение (меньше, равно или больше) между двумя объектами одинакового типа. Можно использовать ICOMPARABLE в качестве основы для алгоритма сортировки. В основе алгоритма сортировки можно использовать делегат метода сравнения, но такой подход не является оптимальным. Возможность сравнения относится к классу, а алгоритм сравнения не изменяется при выполнении, поэтому лучше использовать интерфейс с одним методом.
10. Практика
Для более полного представления того, что я пыталась описать выше, предлагаю для рассмотрения два примера, где использовалось описание и интерфейсов и делегатов с помощью общих типов.
Задачи составлены аналогично друг другу, отличием является лишь условие поиска в массиве.
А именно: 1. Поиск заданного элемента в массиве.
2. Поиск максимального элемента в массиве.
11. Программа 1 using System;
// интерфейс public interface IELEMENT
{ void NEWE();
int summ();
}
// класс реализующий интерфейс public class MYELEMENT: IELEMENT
{ public string name;
public int e1;
public int e2;
// метод для заполнения элементов класса public void NEWE()
{ name = Console. READLINE();
e1 = Convert. TOINT32 (Console. READLINE());
e2 = Convert. TOINT32 (Console. READLINE());
}
// подсчет суммы элементов public int summ()
{ return (e1 e2);
}
}
// описание делегата delegate int Delegate1 (IELEMENT[] arr, int param);
public class Test
{ // метод для поиска элемента с заданной суммой в массиве (если его нет - возвращает -1) static int Find (IELEMENT[] arr, int param)
{for (int i = 1; i < 5; i )
{if (arr[i].summ() == param)
{return i;}} return -1;} public static void Main()
{Delegate1 d1 = new Delegate1 (Find);
IELEMENT[] array1 = new IELEMENT[5];
array1 [0] = new MYELEMENT();
array1 [0].NEWE();
array1 [1] = new MYELEMENT();
array1 [1].NEWE();
array1 [2] = new MYELEMENT();
array1 [2].NEWE();
array1 [3] = new MYELEMENT();
array1 [3].NEWE();
array1 [4] = new MYELEMENT();
array1 [4].NEWE();
int c = d1 (array1,16);
Console. WRITELINE («Номер элемента с заданной суммой:»);
Console. WRITELINE(c);}
}
12. Программа 2 using System;
public interface IELEMENT
{void NEWE();
int summ();} public class MYELEMENT: IELEMENT
{public string name;
public int e1;
public int e2;
public void NEWE()
{name = Console. READLINE();
e1 = Convert. TOINT32 (Console. READLINE());
e2 = Convert. TOINT32 (Console. READLINE());
} public int summ()
{ return (e1 e2);
}
} delegate int Delegate1 (IELEMENT[] arr);
public class Test
{static int MAXELEM (IELEMENT[] arr)
{int n = 0;
int max = arr[0].summ();
for (int i = 1; i < 5; i )
{if (arr[i].summ() > max)
{max = arr[i].summ();
n = i;
}
} return n;
} public static void Main()
{
Delegate1 d1 = new Delegate1 (MAXELEM);
IELEMENT[] array1 = new IELEMENT[5];
array1 [0] = new MYELEMENT();
array1 [0].NEWE();
array1 [1] = new MYELEMENT();
array1 [1].NEWE();
array1 [2] = new MYELEMENT();
array1 [2].NEWE();
array1 [3] = new MYELEMENT();
array1 [3].NEWE();
array1 [4] = new MYELEMENT();
array1 [4].NEWE();
int c = d1 (array1);
Console. WRITELINE («Номер элемента с максимальной суммой:»);
Console. WRITELINE(c);
}
}
Вывод
интерфейс ссылка делегат
В ходе изучения данной темы моей целью было рассмотреть, как используются общие типы при описании интерфейсов и делегатов, и рассмотреть это на примерах задач поиска в массивах.
При детальном изучении данной темы я выяснила, что использование в программе и интерфейсов и делегатов значительно упрощает написание программы и решение поставленной задачи, так как сама программа может быть описана намного короче и стать более просто для понимания.
Список литературы
1) Л.Е. Потапова «Объектно-ориентированное программирование на языке С#»