Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
5400-1.rtf
Скачиваний:
3
Добавлен:
01.07.2025
Размер:
114 Кб
Скачать
☆

Делегаты

Язык программирования C# хотя и допускает, но все же не поощряет использование указателей. В некоторых ситуациях бывает особенно трудно обойтись без указателей на функции. Для этих целей в C# реализованы так называемые делегаты (delegates), которые иногда еще называют безопасными аналогами указателей на функцию. Ниже приведен простейший пример использования метода-делегата:

using System;

delegate void MyDelegate();

class Example_5

{

static void Func()

{

System.Console.WriteLine(«MyDelegate.Func()»);

}

public static void Main()

{

MyDelegate f = new MyDelegate(Func);

f();

}

}

Помимо того что делегаты обеспечивают типовую защищенность, а следовательно, и повышают безопасность кода, они отличаются от обычных указателей на функции еще и тем, что являются объектами, производными от базового типа System.Delegate. Таким образом, если мы используем делегат для указания на статический метод класса, то он просто связывается с соответствующим методом данного класса. Если же делегат указывает на нестатический метод класса, он связывается уже с методом экземпляра такого класса. Это позволяет избежать нарушения принципов ООП, поскольку методы не могут быть использованы отдельно от класса (объекта), в котором они определены.

Еще одним отличием делегатов от простых указателей на функции является возможность вызова нескольких методов с помощью одного делегата. Рассмотрим это на конкретном примере:

using System;

delegate void MyDelegate(string message);

class Example_6

{

public static void Func1(string message)

{

Console.WriteLine(”{0}: MyDelegate.Func1”, message);

}

public static void Func2(string message)

{

Console.WriteLine(”{0}: MyDelegate.Func2”, message);

}

public static void Main()

{

MyDelegate f1, f2, f3;

f1 = new MyDelegate(Func1);

f2 = new MyDelegate(Func2);

f3 = f1 + f2;

f1(”Calling delegate f1”);

f2(”Calling delegate f2”);

f3(”Calling delegate f3”);

}

}

Откомпилировав и выполнив вышеприведенную программу, получим следующий результат:

Calling delegate f1: MyDelegate.Func1

Calling delegate f2: MyDelegate.Func2

Calling delegate f3: MyDelegate.Func1

Calling delegate f3: MyDelegate.Func2

Из этого следует, что вызов метода-делегата f3, полученного с помощью операции сложения f1 + f2, приводит к последовательному выполнению обоих этих методов. Подобно применению операции сложения с целью объединения делегатов, можно использовать и операцию вычитания, которая, как нетрудно догадаться, выполняет обратное действие.

Способы передачи параметров

Анализируя особенности реализации классов языка C#, хотелось бы уделить внимание и способам передачи параметров метода по ссылке. Иногда возникает потребность в том, чтобы функция возвращала сразу несколько значений. Рассмотрим это на примере программы, вычисляющей квадратный корень:

using System;

class Example_7

{

static int GetRoots(double a, double b, double c,

out double x1, out double x2)

{

double d = b * b - 4 * a * c;

if (d > 0)

{

x1 = -(b + Math.Sqrt(d)) / (2 * a);

x2 = -(b - Math.Sqrt(d)) / (2 * a);

return 2;

} else

if (d == 0)

{

x1 = x2 = -b / (2 * a);

return 1;

} else

{

x1 = x2 = 0;

return 0;

}

}

public static void Main()

{

double x1, x2;

int roots = GetRoots(3, -2, -5, out x1, out x2);

Console.WriteLine(”roots #: {0}”, roots);

if (roots == 2)

Console.WriteLine(”x1 = {0}, x2 = {1}”, x1, x2);

else

if (roots == 1)

Console.WriteLine(”x = {0}”, x1);

}

}

Чтобы функция GetRoots возвращала оба корня уравнения (x1 и x2), мы указали транслятору, что переменные x1 и x2 должны быть переданы по ссылке, применив для этого параметр out. Обратите внимание на то, что нам не обязательно инициализировать переменные x1 и x2 перед вызовом функции GetRoots. Обозначив функцию ключевым словом out, мы добьемся того, что ее аргументы могут использоваться только для возврата какого-то значения, но не для его передачи внутрь функции. Таким образом, подразумевается, что переменная будет инициализирована в теле самой функции. В случае же, если нам по какой-то причине потребуется передать в параметре функции некоторое значение с возможностью его последующего изменения, можно воспользоваться параметром ref. Действие этого параметра очень похоже на действие out, но он позволяет еще и передавать значение параметра телу функции. Второе отличие ключевого слова ref состоит в том, что передаваемый параметр функции должен быть инициализирован предварительно.

Такой метод очень напоминает использование параметра var в списке аргументов функций, принятое в языке программирования Паскаль, и является еще одним отличием от языка Java, где параметры всегда передаются по значению.

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]