Главная » C# » Нахождение комнатной группировки приложения управления освещением в Visual C# (Sharp)

0

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

следующий элемент списка до тех  пор,  пока не будет найдена требуемая  групповка. Код для этой операции выглядит таким образом:

public object FindRoomGrouping(string description) { RoomGrouping curr = _roomGroupings.Next as RoomGrouping; while (curr != null) {

if (curr.Description.CompareTo(description) == 0) {

return curr;

}

curr = curr.Next as RoomGrouping;

}

return null;

}

Данный код цикла похож на код цикла, рассмотренный в разд. "Сохранение  коекции с помощью связанного списка" ранее в этой главе. Единственная разница заключается в том, что переменная curr имеет тип RoomGrouping, и т. к. Next отнится к типу BaseLinkedList, то требуется выполнить приведение типов. Цикл выполняется  с  помощью  оператора   while и   при   каждой   итерации   цикла curr .Description сравнивается с параметром description. Если требуемый обкт обнаружен, то возвращается дескриптор RoomGrouping; в противном случае воращается значение null.

Этот метод используется таким образом:

object foundHandle = controller.FindRoomGrouping("description");

Но связанный список комнатных группировок является коллекцией, к которой можно обращаться, как к массиву. В языке С# имеются конструкции, с помощью корых класс LightingController можно снабдить функциональностью массива, нываемой индексатором. Далее приводится код метода класса LightingController, который выполняет данную операцию:

public object this[string description] { get {

return FindRoomGrouping(description);

}

}

Индексатор объявляется подобно свойству, за исключением того, что в качестве идентификатора свойства используется ключевое слово this, после которого слуют заключенные в фигурные скобки параметры массива. Возвращаемый индеатором тип указывается идентификатором перед ключевым словом this. В даом примере определена только часть get индексатора, поэтому доступ к нему предоставляется только для чтения. Данный индексатор можно использовать слующим образом:

object foundHandle = controller["description"];

Таким образом, с помощью индексатора можно определить доступ к массиву посредством иных, нежели числовых, индексов.

ПРИМЕЧАНИЕ

Индексаторы  предоставляют  сервисную  функциональность,  и  их  лучш е  всего  встаять в классы, управляющи е коллекциями. Класс LightingController, который управляет коллекцией комнатных группировок, является хороши м кандидатом для снабжени я   индексатором.

Определенную комнатную группировку можно найти с помощью методов или иексатора класса LightingController. Но иногда пользователю требуется инфоация обо всех имеющихся комнатных группировках. Для этого можно определить числовой индексатор и обработать в цикле отдельные элементы. Соответствующий код будет выглядеть так:

public string this[int index]  { get { }

}

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

ПРИМЕЧАНИЕ

Ти п   может   иметь   несколько   определений   индексаторов,   но   все   они   должн ы   иметь разные  параметр ы  массива.

Допустим, что у нас имеется числовой индексатор. Для обработки в цикле отделых комнатных группировок мы можем использовать такой код:

for (int cl = 0; cl < controller.Length; cl ++) { string description = controller[cl];

}

В то время как данный код цикла является приемлемым, в нем необходимо добить свойство Length в класс LightingController. Лучшим подходом будет иользование ключевого слова foreach таким образом:

foreach (string description in controller.RoomGroupinglterator()) {

// Выполняется какая-либо операция с описанием.

}

Данный код предпочтительней, т. к. оператор foreach имеет более простой синтаис. Не играет роли, что мы потеряли информацию о том, какое смещение относия  к  какому  описанию,  т. к.  эта  информация  все  равно  не  представляет  никакой ценности. Не забывайте, что мы имеем дело со связанным списком, элементы в кором  могут  размещаться  в  любом  порядке.  Поэтому  числовой  идентификатор’ в данном случае совершенно бесполезен. Единственным надежным способом найти комнатную группировку является наличие ее описания или специфичного для коекции индекса.

ПРИМЕЧАНИЕ

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

Так   как   класс   LightingController не   имеет   встроенной   функциональности foreach, необходимо прибегнуть  к помощи  ключевого слова yield, чтобы добить ее. Далее приводится код для реализации цикла с помощью ключевого слова yield. (В самом начале файла LightingController необходимо добавить оператор using System. Collections;, чтобы получить доступ К интерфейсу I Enumerable.) public IEnumerable RoomGroupinglterator() {

RoomGrouping curr = _roomGroupings.Next as RoomGrouping; while (curr != null) {

yield return curr.Description;

curr = curr.Next as RoomGrouping;

}

}

В итераторе с помощью переменной curr создается другой цикл for, но для нас важным является код, выделенный жирным шрифтом. Здесь ключевое слово yield используется совместно с ключевым словом return. Ключевое слово return не следует рассматривать отдельно, как указывающее выход из функции. В данном случае ключевые слова yield и return составляют одну цельную конструкцию, применяемую для передачи сообщений.

Ключевое слово yield всегда доставляет разработчикам большие трудности с его пониманием. Самым лучшим способом понять его будет исследование, как оно ротает совместно с ключевым словом foreach:

1. Когда код доходит до оператора foreach, устанавливается контекст, в котором элементы коллекции обрабатываются в итераторе. Установка контекста состоит в получении коллекции и выделении места для отдельного элемента.

2. Вызывается итератор коллекции, что для данного примера означает вызов мето-

да RoomGroupinglterator() .

3. Метод RoomGroupingiterator () присваивает переменной curr значение, указывающее на первый элемент двунаправленного списка комнатных группировок.

4. Начинается  выполнение  цикла,  продолжающееся  до  тех  пор,  пока  значение

curr не станет равным нулю.

5. Код доходит до комбинации yield return, означающей, что результат после ключевого слова return нужно сохранить в области памяти для отдельного элемента, выделенной в шаге 1.

6. Код создает закладку, помечающую последний исполненный оператор в итероре, и переходит обратно к оператору f oreach.

7. Оператор foreach продолжает выполнение кода, которым в данном примере является комментарий

// Выполняется какая-либо операция с описанием.

8. Когда оператор foreach приступает к выполнению следующей итерации, извлается ранее сохраненная закладка и исполнятся код, следующий сразу же после закладки. В  результате  исполняется  код  curr=curr .Next as RoomGrouping В методе RoomGroupingiterator ().

9. Исполнение итератора продолжается, и шаги 4—9 выполняются  до  тех  пор, пока значение curr не станет равным нулю.

10.                       Когда значение  curr становится равным нулю, выполнение итератора прекрается, вызывая остановку цикла foreach.

Частью, трудно поддающейся пониманию, является механизм, применяемый, когда конструкция yield return вызывает прекращение исполнения с последующим его возобновлением. Программисты не привыкли к тому, что можно выходить и вхить в метод и продолжать исполнение. Но не забывайте, что это можно делать только в контексте комбинации оператора foreach и конструкции yield return. Этот механизм, основанный на использовании закладок, неприменим в С# ни в кой другой ситуации.

В этом примере было показано применение ключевого слова yield в  цикле,  но цикл не является обязательным. Так в следующем фрагменте кода yield использтся в коллекции из трех чисел:

public IEnumerable Numberlterator() { yield return 1;

yield return 2;

yield return 3;

}

ВАЖНОСТЬ      ИНДЕКСАТОРОВ      И     КЛЮЧЕВОГО      СЛОВА        "YIELD"

В примере для этой главы демонстрируется использование индексаторов  и  ключевого слова yiel d дл я придания типу вида  обычной  коллекции.  Использование  данного примера  имеет определенную  цель.  Но  хороший ли  это  пример?  Я  пытаюсь  научить  вас,

как писать программное обеспечение профессионально на высоком  уровне,  т.  е.  наить вас инженерии разработки ПО. Умение  работать  со  связанными  списками  явлтся  частью  этой  инженерии  разработки  ПО,  но  используются  ли  связанные  списки в сегодняшнем программировании? Не очень. Так нужно ли  современным  программтам знать о связанных списках? Конечно же, точно так же как необходимо знать, как выполнять арифметические операции,  хотя для  выполнения  их мы  сегодня  пользуея не карандашом и бумагой,  а калькулятором.

Таким образом, если пример иллюстрирует некоторые возможности С#, но в действельности мы вряд ли будем делать что-либо подобное показанному  в  примере.  Пезны ли эти возможности? Да, эти возможности  полезны.  Представьте, что вы строе  дом   и   вам   необходимы   стропила  для   крыши.   Чтобы   ускорить   сборку  стропил и чтобы они были наиболее одинаковые, вы сначала делаете приспособление для удерживания  компонентов  стропил   необходимым  образом.  Данные  приспособления не используются непосредственно в строительстве дома, они служат лишь  для  ускения сборки элементов  его  конструкции.  Подобным  образом  индексаторы  и  ключое слово yield упрощают и ускоряют разработку классов, соответствующих стаартной  парадигме  программирования  на языке С#.

Иногда приходится создавать конструкционные классы, которые  не  делают  ничего, кроме как обеспечивают работоспособность других компонентов, выполняющих пезную работу. Вот для создания конструкционных классов нам и понадобятся индеаторы, а также ключевое слово yield. Так что думайте об индексаторах и ключевом слове yield как о механизме, который позволяет множественным элементам  выглеть,  как коллекция С#.

Источник: Гросс  К. С# 2008:  Пер. с англ. — СПб.:  БХВ-Петербург, 2009. — 576 е.:  ил. — (Самоучитель)

По теме:

  • Комментарии