Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
CSharp Language Specification.doc
Скачиваний:
13
Добавлен:
26.09.2019
Размер:
4.75 Mб
Скачать

1.11Делегаты

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

В следующем примере объявляется и используется тип делегата Function.

using System;

delegate double Function(double x);

class Multiplier { double factor;

public Multiplier(double factor) { this.factor = factor; }

public double Multiply(double x) { return x * factor; } }

class Test { static double Square(double x) { return x * x; }

static double[] Apply(double[] a, Function f) { double[] result = new double[a.Length]; for (int i = 0; i < a.Length; i++) result[i] = f(a[i]); return result; }

static void Main() { double[] a = {0.0, 0.5, 1.0};

double[] squares = Apply(a, Square);

double[] sines = Apply(a, Math.Sin);

Multiplier m = new Multiplier(2.0); double[] doubles = Apply(a, m.Multiply); } }

Экземпляр типа делегата Function может ссылаться на любой метод, который принимает аргумент и возвращает значение типа double. Метод Apply применяет заданную функцию Function к элементам массива double[] и возвращает массив double[], содержащий результаты. В методе Main метод Apply используется для применения трех различных функций к массиву double[].

Делегат может ссылаться как на статический метод (например, Square или Math.Sin в предыдущем примере), так и на метод экземпляра (например, m.Multiply в предыдущем примере). Делегат, ссылающийся на метод экземпляра, также ссылается на конкретный объект. При вызове такого метода экземпляра с помощью делегата этот объект становится объектом this.

Делегаты также могут создаваться с помощью анонимных функций, которые представляют собой «встроенные методы», создаваемые в процессе выполнения. Анонимные функции могут видеть локальные переменные окружающих их методов. Таким образом, приведенный выше пример множителя может быть записан проще с использованием класса Multiplier:

double[] doubles = Apply(a, (double x) => x * 2.0);

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

1.12Атрибуты

Типы, члены и другие сущности C# поддерживают модификаторы, которые управляют определенными аспектами их поведения. Например, доступность метода управляется с помощью модификаторов public, protected, internal и private. Благодаря этой возможности в C# пользовательские типы декларативных сведений могут быть вложены в сущности программы и извлекаться во время выполнения. Такие дополнительные декларативные сведения задаются в программе посредством определения и использования атрибутов.

В следующем примере атрибут HelpAttribute присоединяется к сущностям программы и предоставляет ссылки на связанную с ними документацию.

using System;

public class HelpAttribute: Attribute { string url; string topic;

public HelpAttribute(string url) { this.url = url; }

public string Url { get { return url; } }

public string Topic { get { return topic; } set { topic = value; } } }

Все классы атрибутов наследуются от базового класса System.Attribute, предоставляемого платформой .NET Framework. Чтобы применить атрибут, необходимо указать его имя и любые другие аргументы в квадратных скобках непосредственно перед связанным объявлением. Если имя атрибута заканчивается словом Attribute, при ссылке на него эту часть имени можно опустить. Например, атрибут HelpAttribute можно использовать следующим образом.

[Help("http://msdn.microsoft.com/.../MyClass.htm")] public class Widget { [Help("http://msdn.microsoft.com/.../MyClass.htm", Topic = "Display")] public void Display(string text) {} }

В этом примере атрибут HelpAttribute присоединяется к классу Widget, а другой атрибут HelpAttribute — к методу Display класса. Общие конструкторы класса атрибута управляют сведениями, которые предоставляются при вложении атрибута в сущность программы. Дополнительные сведения предоставляются посредством ссылки на открытые свойства для чтения и записи класса атрибута (например, ссылка на свойства Topic в предыдущем примере).

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

using System; using System.Reflection;

class Test { static void ShowHelp(MemberInfo member) { HelpAttribute a = Attribute.GetCustomAttribute(member, typeof(HelpAttribute)) as HelpAttribute; if (a == null) { Console.WriteLine("No help for {0}", member); } else { Console.WriteLine("Help for {0}:", member); Console.WriteLine(" Url={0}, Topic={1}", a.Url, a.Topic); } }

static void Main() { ShowHelp(typeof(Widget)); ShowHelp(typeof(Widget).GetMethod("Display")); } }

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

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