Разбираемся с делегатами

Приветствую всех, сегодня хотел затронуть тему о делегатах, и их применения.

Для работы с делегатами нам необходимо объявить тип делегата и тип указателей на метод оно и будет именем делегата.

Который в нашем случаи принимает число в качестве аргумента и возвращает так же число. Делегаты имеют уровень класса и объявляются в пространстве имен. А их объявление должно начинаться с ключевого слова delegate. Делегаты могут быть использованы для вызова как статических методов, так и методов экземпляра. После того как создан делегат мы можем объявить поле:

Однако применения поля в моем примере я не использовал, так как оно лишне, поля используют с ключевым словом event после public  который объявляет событие в классе. Но об этом мы поговорим позже.

Поле делегата мы создали, теперь создадим метод на который будет указывать делегат:

Имя метода может быть любым, однако принимать и возвращать он должен один и тот же тип что и делегат. Стоит помнить тип может быть возвращаемым или нет void, по аналогии с методами, он в целом и похож на метод, за исключением того что он у него нет тела, но это только внешне, в работе он отличается от методов.

Рассмотрим полностью код программы:

Рассмотрим код программы. Вызываем метод Calc и передаем в качестве параметра methodSquare и число 12. Если бы мы рассматривали обычный метод, то по определению должен был бы вызваться метод metodSquare, но с делегатами происходит вызов Calc. Внутри которого входим в цикл for и вызывается метод methodSquare, так как аргумент который  мы приняли имел тип nameDelegat в переменной f это указатель делегата на метод. Произошел вызов methodSquare который произвел вычисления и вернул результат в метод Calс, в котором продолжился цикл for, по окончанию которого результат был передан в метод Main в консоль.

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

Следующий пример показывает как с помощью делегата, используя анонимные методы и лямбда-метод вычислить арифметическое среднее:

Как использовать дженерики внутри делегатов?

Приведенный пример ниже, покажет как использовать в делегатах дженерики:

 

Метод methodSquare получил перегрузку метода, он может принимать как тип int так и double. Однако я сделал метод Calc обобщающим (универсальным) он принимает любой тип данных, а делегат уже сам определяет какую из перегрузок ему выбрать.

Однако мы можем воспользоваться упрощенным вариантом использования делегата, без его объявления, а использовать его в параметре метода Calc встроенный, для этого посмотрим код ниже:

В приведенном примере выше мы в методе Calc воспользовались встроенным делегатом в Net который принимает T, а возвращает int.

Стоит запомнить что первые параметры Func всегда будут те что принимает делегат, а последним то что отдает.

Что такое анонимный делегат?

Это способ записи методов, а нужен он лишь для того что бы сократить функциональный код вашей программы. Посмотрим пример выше и используем анонимный делегат:

 

Что же мы видим, функционал метода methodSquare мы вынесли в строку вызова метода Calc, из метода Main, если воспользоваться отладчиком то мы увидим, что компилятор создал за нас метод methodSquare только назвал его иначе, и воспользовался нашим функционалом вычисления так как мы его передали сами.

Как использовать Лямда-выражение в делегатах?

Лямда -выражения это стиль записи, который позволяет еще больше сократить код программы. Мы это и сделаем из нашего примера:

Как видите использование лямда-выражения уменьшило код почти в два раза в методе вызова делегата. Что касается кода использованного в лямда-выражении, мы видим что он берет i => и возвращает квадратный корень от i

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

Еще хотело упомянуть об одной особенности лямбда-выражения в делегатах так называемом Замыкании.

Мы знаем что при использовании делегатов в лямбда-выражении, создается анонимный метод который принимает и производит вычислений, при использовании полей и локальных переменных, создаются ссылки на них и они используются как анонимные методы. Вы спросите о чем я? Сейчас все увидите на примере ниже:

Как вы думаете что будет выведено в консоль? Подумали? Подумайте еще… Могу сказать что вы подумали о том что будет выведено 1,2,3,4…11 Однако это не так. А все дело в том что создалась ссылка на переменную i которая изменяла свое значение и меняло его во всем листе, в начале были все листы 1, потом 2 пока они все имели значения 11. А все потому что мы в лямбда-выражении передали переменную i из цикла. А как же использовать тогда этот вариант правильно, для этого надо завести локальную переменную в цикле, ее и передавать, рассмотрим пример:

 

Теперь результат будет тот который мы и ожидали первоначально 1,2,3,4,5

 

 

Обновлено: 22.03.2018 — 20:16

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Этот сайт использует Akismet для борьбы со спамом. Узнайте, как обрабатываются ваши данные комментариев.