Я прочитал несколько статей о делегатах, и да, сначала синтаксис запутан. Я нашел эту статью наиболее полезной. Пример 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
. Как и в учебнике, эти функции кажутся нормальными, с обычным типом их атрибутов, но здесь атрибуты относятся к типу функций делегата, и я получаю смущение.
Не могли бы вы немного рассказать мне об этом?
Делегат - это всего лишь тип. С типами, к которым вы привыкли (например, 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
Тип делегата для всех целей и целей является просто функцией (или если вы C++ пользователь, сродни указателю функции). Другими словами, вы называете их точно так же, как если бы они были функцией, и это именно то, что делает образец кода.
f(i)
вызывает переданную функцию с переменной i
качестве ее единственного аргумента, как и выглядит.
Act
иFilter
функцииf(i)
иp(i)
являются функциями, которые я передаю в качестве аргументовAct
иFilter
и я решаю, что они делают, создавая свои тела (то есть вMain
функции класса)?