В C# нет указателей (про unsafe я молчу). И это хорошо и правильно – указатель он по сути своей не типизирован. Передали в метод ссылку, а как ее интерпретировать – на совести принимающей стороны. Можем передать int, а использовать как float. И т.д. Тоже самое касается и методов – передали указатель на метод с одной сигнатурой, а используем совсем по-другому…
Зато в C# есть делегаты. Я бы назвал делегаты “типизированные указатели на методы”. Покажу на примере как это работает.
Сначала нужно описать тип делегата, т.е. сигнатуру метода. Описание можно не привязывать к конкретному классу:
namespace DelegateTest
{
public delegate decimal GetVarValue(string name);
Здесь метод имеет один параметр типа string и возвращает decimal.
Теперь этот делегат мы можем использовать при описании параметров и переменных:
public class Parser
{
/// <summary>
/// Описание переменной, сохращающей делегат
/// </summary>
private GetVarValue getVarValueHandler;
/// <summary>
/// Передаем делегат в конструктор
/// </summary>
/// <param name="getVarValueHandler"></param>
public Parser(GetVarValue getVarValueHandler)
{
// Сохраняем делегат, т.к. хотим использовать его
// в другом методе этого класса
this.getVarValueHandler = getVarValueHandler;
}
/// <summary>
/// Метод расчета
/// </summary>
/// <returns></returns>
public decimal Calc()
{
decimal result = 0;
// Вызываем делегат с параметром var1
result += getVarValueHandler("var1");
// Вызываем делегат с параметром var2
result += getVarValueHandler("var2");
return result;
}
Описание переменной типа делегат выглядит совершенно так же как и обычной переменной. Переменная getVarValueHandler имеет тип GetVarValue, т.е. тип делегата с нашей сигнатурой. Отличие от переменной в том, что мы можем вызывать этот метод. Разумеется, вызывать его можно только так, как он описан, т.е. с одним параметром типа string:
getVarValueHandler("var1");
Прелесть в том, что никак иначе вызвать метод по этой ссылке (а передали мы фактически ссылку на метод) нельзя. Только так, как метод описан в описании делегата.
Использовать этот класс тоже очень просто. Во-первых, нам потребуется метод, который мы будем передавать в конструктор нашего класса. Наверное, излишне говорить, что сигнатура этого метода должна совпадать с сигнатурой делегата и передать в конструктор что-то другое нельзя:
class Program
{
static void Main(string[] args)
{
// Передаем в конструктор делегат, т.е. ссылку
// на наш метод
Parser parser = new Parser(GetVarValueMethod);
// Вызываем метод Calc
Console.WriteLine(parser.Calc());
}
/// <summary>
/// Делегат. Имя у него может быть любое, главное
/// чтобы сигнатура была той как описана в типе
/// делегата
/// </summary>
static decimal GetVarValueMethod(string name)
{
Console.WriteLine("Value of {0}:", name);
return decimal.Parse(Console.ReadLine());
}
}
Имя метода может быть может быть любое, главное чтобы сигнатура совпадала с сигнатурой делегата.
Вот и все. Теперь при вызове метода Calc будет два раза вызван метод GetVarValueMethod.
No comments:
Post a Comment