Пояснение к этому коду с делегатами

1

Я прочитал несколько статей о делегатах, и да, сначала синтаксис запутан. Я нашел эту статью наиболее полезной. Пример 2 позволяет понять, как использовать делегатов. Но у меня есть этот код, данный мне и работаю с ним:

public delegate bool IntPredicate(int x);
public delegate void IntAction(int x);

class IntList : List<int>
{
    public IntList(params int[] elements) : base(elements)
    {

    }

    public void Act(IntAction f)
    {
        foreach (int i in this)
        {
            f(i);
        }
    }
    public IntList Filter(IntPredicate p)
    {
        IntList res = new IntList();
        foreach (int i in this)
            if (p(i))
                res.Add(i);
        return res;
    }
}

Теперь меня смущает переменная f и p в функциях Act и Filter. Как и в учебнике, эти функции кажутся нормальными, с обычным типом их атрибутов, но здесь атрибуты относятся к типу функций делегата, и я получаю смущение.

Не могли бы вы немного рассказать мне об этом?

Теги:
delegates

2 ответа

3
Лучший ответ

Делегат - это всего лишь тип. С типами, к которым вы привыкли (например, int, string и т.д.), Когда вы хотите их использовать, вы либо используете тот, который находится в рамках, либо объявляете свой собственный. Вы можете сделать то же самое с делегатами - либо использовать предварительно построенный (например, System.Action), либо объявить свой собственный, что и было сделано здесь.

Итак, в вашем фрагменте кода объявлены 3 типа:

public delegate bool IntPredicate(int x);
public delegate void IntAction(int x);

class IntList : List<int> { ... }

Вы заметите, что объявления делегатов находятся на том же уровне, что и объявление класса.

Когда у вас есть тип (например, ваш IntPredicate), вы можете использовать его для переменных или параметров функции. Теперь вопросы: как вы устанавливаете значение переменной и что вы будете с ней делать?

С обычными переменными вы просто передаете значение. Как это:

string text = "Hello world";

Принцип один и тот же с делегатами, но, конечно же, вам нужно передать что-то типа делегата или что-то, что может быть преобразовано в него. У вас есть несколько вариантов:

Существующий метод

Вы можете передать метод, если его подпись (то есть возвращаемое значение и параметры) соответствует таковой из делегата. Итак, вы можете сделать это:

void WriteIntAction(int value)
{
    Console.WriteLine(value);
}

/* then, in some other method */
IntList intList = new IntList(1,2,3);
intList.Act(WriteIntAction);

Анонимный метод

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

IntList intList = new IntList(1,2,3);
intList.Act(x => Console.WriteLine(x));

Итак, после того, как ваша переменная настроена с помощью метода, который вам нужен (будь то существующий или анонимный), вы можете просто использовать переменную делегата, как и любой метод. Вот что делает эта строка:

f(i);

Просто имейте в виду, что делегат является ссылочным типом, поэтому значение f здесь может быть null, а затем генерирует исключение при попытке вызвать делегата.

TL; DR

Делегат - это тип. Вы можете использовать его в переменной или параметре метода. Вы можете передать метод только с использованием его имени или вы можете создать анонимный метод. Затем вы можете вызвать метод, которым вы его передали, используя переменную так же, как и метод.

Вы можете прочитать больше онлайн, например здесь: http://msdn.microsoft.com/en-us/library/ms173171.aspx

  • 0
    +1 действительно хорошее объяснение, я бы не сказал это лучше.
  • 0
    Отличное объяснение! Большое спасибо! Я просто хочу сказать одну вещь, чтобы понять, правильно ли я понял: в области Act и Filter функции f(i) и p(i) являются функциями, которые я передаю в качестве аргументов Act и Filter и я решаю, что они делают, создавая свои тела (то есть в Main функции класса)?
Показать ещё 1 комментарий
1

Тип делегата для всех целей и целей является просто функцией (или если вы C++ пользователь, сродни указателю функции). Другими словами, вы называете их точно так же, как если бы они были функцией, и это именно то, что делает образец кода.

f(i) вызывает переданную функцию с переменной i качестве ее единственного аргумента, как и выглядит.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню