Делегаты. Часть 4. Анонимные функции. Анонимные методы. Возврат значения. Передача параметров

Делегаты. Часть 4. Анонимные функции. Анонимные методы. Возврат значения. Передача параметров


Содержание



1. Что называется анонимной функцией?

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

 

2. Какие в C# существуют виды анонимных функций?

В языке программирования C# реализовано 2 вида анонимных функций:

 

3. В каких случаях целесообразно использовать анонимные функции?

Часто бывает так, что делегат ссылается только на один метод и большее ни на какой другой. Сам же метод непосредственно не вызывается никогда. В этом случае имя метода можно не использовать, а описать только блок программного кода метода. Язык программирования C# предусматривает объявление кодового блока метода, который будет передаваться конструктору делегата. То есть, объявляется безымянный блок программного кода.

 

4. Преимущества использования анонимных функций

Использование анонимных функций дает следующие преимущества:

  • простота использования;
  • отсутствие объявления отдельного метода, предназначенного строго для передачи его делегату.

 

5. Какая общая форма объявления анонимного метода, который не возвращает значения и не получает параметров?

Если метод не возвращает и не получает параметров (void), то общая форма такого метода следующая:

delegate
{
    // Программный код метода
    // ...
}

 

6. Пример использования анонимного метода, который не возвращает значения

Задача

Пусть дано приложение, созданное по шаблону Windows Forms Application — C#. В этом приложении главной форме соответствует класс Form1, который имеет следующий вид:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace TrainDelegates04
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }
    }
}

Продемонстрировать вызов метода, который не получает и не возвращает значение. Метод выводит на форму текст приветствия «Hello world!!!».

Выполнение

1. Объявить тип делегата с именем HELLO

// объявление типа делегата, который не получает и не возвращает значение
delegate void HELLO();

2. Разместить на форме элемент управления типа Button. В результате будет создан объект с именем button1.

3. Запрограммировать обработчик события клика на кнопке button1. В обработчике события набрать следующий программный код

// Вывод текста 'Hello world!!!' через делегат
// Делегат носит имя HW, метод - безымянный
HELLO HW = delegate
{
    // программный код метода
    label1.Text = "Hello world!";
};

// вызов анонимного метода с помощью делегата
HW();

Общий программный код модуля «Form1.cs», описывающего класс формы Form1:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace TrainDelegates04
{
    public partial class Form1 : Form
    {
        // объявление типа делегата, который не получает и не возвращает значения
        delegate void HELLO();

        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            // Вывод текста 'Hello world!!!' через делегат
            // Делегат носит имя HW, метод - безымянный
            HELLO HW = delegate
            {
                // программный код метода
                label1.Text = "Hello world!";
            };

            // вызов анонимного метода с помощью делегата
            HW();
        }
    }
}

 

7. Как анонимному методу передать аргументы (параметры)? Общая форма анонимного метода, который получает параметр и не возвращает значения

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

delegate (список_параметров)
{
    // Программный код метода
    // ...
}

где список_параметров – это один или несколько параметров, которые передаются делегату. Правила передачи списка параметров такие же, как и при передаче параметров методу (функции).

 

8. Как реализовать возврат значения из анонимного метода?

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

delegate (список_параметров)
{
    // Программный код метода
    // ...

    return величина;
}

где величина – переменная, выражение или значение, которое возвращается из делегата.

 

9. Пример вызова анонимного метода, который возвращает значение и получает параметры (аргументы)

Задача

Реализовать функцию, которая находит площадь треугольника по формуле Герона. Функция получает входным параметром значения трех сторон треугольника a, b, c.
Если введены некорректные значения a, b, c, то функция возвращает -1 (отрицательное число).

Выполнение

Объявить тип делегата в теле класса (например, класса формы Form1 для приложений типа Windows Forms Application).

// Объявление типа делегата
delegate float SquareTriangle(float a, float b, float c);

Реализовать в другом программном коде (например, обработчике события) метод вычисления площади треугольника по формуле Герона.

// Объявление делегата с именем ST, вычисляющего площадь треугольника
SquareTriangle ST;
ST = delegate(float a, float b, float c)
{
    float s, p, d;

    p = (a + b + c)/2.0f;
    d = p*(p-a)*(p-b)*(p-c);
    if (d<0) return -1.0f;

    s = (float)Math.Sqrt(p*(p-a)*(p-b)*(p-c));

    return (float)s;
};

// Вызов делегата
float area;
area = ST(2.0f, 3.0f, 2.2f); // area = 2.199636
area = ST(3.0f, 4.0f, 5.0f); // area = 6.0
area = ST(1.0f, 5.0f, 7.0f); // area = -1.0 - неверные входные данные

Более подробно данный пример описан в статье:

 

10. Какие особенности применения внешних переменных в анонимных методах?

В анонимных методах можно использовать внешние переменные. Внешние переменные для анонимных методов – это локальные переменные метода, из которого вызывается анонимный метод.

Пример

Пусть в некотором классе объявлена внешняя переменная a и тип делегата CalcA:

// внешняя переменная a
private int a;

// тип делегата CalcA
delegate void CalcA();

Фрагмент кода, который демонстрирует использование переменной a в обработчике события или другом методе этого же класса:

// Объявление анонимного метода без параметров
CalcA IncrA = delegate
{
    // "захват" внешней переменной a
    a = a + 1; // инкремент
};

// Демонстрация использования ("захват") внешней переменной a
a = 8;

IncrA(); // a = 9
IncrA(); // a = 10

 

11. Что означает термин «захват переменной»? Пример

Термин «захват переменной» означает использование внешней переменной в анонимном методе. Захваченная переменная существует до тех пор, пока делегат, который ее захватил, не будет «собран в мусор».

Более подробно о «сборе мусора» описано в теме:

Пример

В примере продемонстрирован «захват» переменной a. Пример приведен для приложения типа Windows Forms Application. В классе основной формы объявлены два типа делегатов с именами CalcA1, CalcA2.

В обработчике события объявлено два делегата:

  • делегат IncrA типа CalcA1. Этот делегат увеличивает на 1 значение внешней переменной a;
  • делегат IncrA2 типа CalcA2. Этот делегат увеличивает значение внешней переменной a на 2.

Делегаты Incr и Incr2 осуществляют «захват» внешней переменной a.
Весь текст модуля «Form1.cs» следующий:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace TrainDelegates07
{
    public partial class Form1 : Form
    {
        // внешняя переменная a
        private int a;

        // тип делегата CalcA1
        delegate void CalcA1();

        // тип делегата CalcA2
        delegate void CalcA2();

        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            // Объявление анонимного метода
            CalcA1 IncrA = delegate
            {
                // "захват" внешней переменной a
                a = a + 1; // увеличение a на 1
            };

            // анонимный метод Incr2
            CalcA2 IncrA2 = delegate
            {
                // "захват" внешней переменной a
                a = a + 2; // увеличение a на 2
            };

            // Демонстрация "захвата" внешней переменной a
            a = 8;

            IncrA(); // a = 9
            IncrA(); // a = 10

            IncrA2(); // a = 12, взято предшествующее значение a
        }
    }
}

 


Связанные темы