Затем было рассмотрено ключевое слово C# delegate, которое используется для непрямого построения классов, производных от System.MulticastDelegate. Как выяснилось, делегат представляет собой объект, хранящий список методов, доступных для вызова. При этом вызовы, могут быть синхронными (они выполняются с помощью метода Invoke()) или асинхронными (они выполняются с помощью методов BeginInvoke() и EndInvoke()). Асинхронная природа типов делегата .NET будет рассмотрена позже.
Ключевое слово C# event при использовании с типом делегата позволяет упростить процесс отправки сообщений событий вызывающим объектам. Как показывает генерируемый CIL-код, модель событий .NET сводит ситуацию к скрытым вызовам типов System.Delegate/System.MulticastDelegate. В этой связи ключевое слово C# event оказывается необязательным и просто экономит время при наборе текста программы.
Новая возможность, появившаяся в C# 2005 и получившая название анонимных методов , позволяет непосредственно ассоциировать с событием (неименованный) блок операторов программного кода. Анонимные методы могут игнорировать параметры, посылаемые событием, и получать доступ в "внешним переменным" определяющего метода. В завершение главы был рассмотрен упрощенный способ регистрации событий с помощью группового преобразования методов.
ГЛАВА 9. Специальные приемы построения типов
В этой главе вы расширите горизонты вашего понимания языка C#, рассмотрев ряд более сложных (но весьма полезных) синтаксических конструкций. Сначала мы с вами выясним, как использовать метод индексатора. Этот механизм в C# позволяет строить пользовательские типы, обеспечивающие доступ к внутренним подтипам на основе синтаксиса массивов. Научившись строить методы индексатора, вы затем узнаете, как перегружать различные операции (+, -, ‹, › и т.д.) и явно или неявно создавать пользовательские подпрограммы преобразования типов (а также узнаете, зачем это может понадобиться).
Во второй половине главы будет рассмотрен небольшой набор ключевых слов C#, которые позволяют реализовать весьма интересные конструкции, хотя используются не очень часто. Вы узнаете о том, как с помощью ключевых слов checked и unchecked программно учитывать условия переполнения и потери значимости, а также о том, как создается "небезопасный" программный контекст, обеспечивающий возможность непосредственного управления ссылочными типами в C#. Завершается глава обсуждением роли директив препроцессора C#.
Создание пользовательских индексаторов
Как программисты, мы прекрасно знаем, что с помощью индексов можно получить доступ к отдельным элементам, содержащимся в стандартном массиве.
// Объявление массива целых значений.
int[] myInts = {10, 9, 100, 432, 9874};
// Использование операции [] для доступа к элементам.
for (int j = 0; j ‹ myInts.Length; j++) Console.WriteLine("Индекс {0} = {1}", j, myInts[j]);
Этот программный код ни в коем случае не претендует на новизну. Но язык C# дает возможность строить пользовательские классы и структуры, которые могут индексироваться подобно стандартным массивам. Поэтому совсем не удивительно, что метод, который обеспечивает такой доступ к элементам, называется индекса-mopoм.
Перед тем как приступить к созданию соответствующей конструкции, мы рассмотрим один пример. Предположим, что поддержка метода индексатора уже добавлена в пользовательскую коллекцию Garage (гараж), уже рассматривавшуюся в главе 8. Проанализируйте следующий пример ее использования.
// Индексаторы обеспечивают доступ к элементам подобно массивам.
public class Program {
static void Main(string[] args) {
Console.WriteLine("***** Забавы с индексаторами *****\n");
// Предположим, что Garage имеет метод индексатора.
Garage carLot = new Garage();
// Добавление в гараж машин с помощью индексатора.
сarLot[0] = new Саr("FееFee", 200);
carLot[1] = new Car("Clunker", 90);
carLot[2] = new Car("Zippy", 30);
// Чтение и отображение элементов с помощью индексатора.
for (int i = 0; i ‹ 3; i++) {
Console.WriteLine("Hомep машины: {0}", i);
Console.WriteLite("Нaзвaниe: {0}", carLot[i].PetName);
Console.WriteLine("Максимальная скорость: {0}", carLot[i].CurrSpeed);
Console.WriteLine();
}
Console.ReadLine();
}
}
Как видите, индексаторы ведут себя во многом подобно пользовательской коллекции, поддерживающей интерфейсы IEnumerator и IEnumerable. Основное различие в том, что вместо доступа к содержимому посредством типов интерфейса вы можете работать с внутренней коллекцией автомобилей, как с обычным массивом.
Читать дальше