Разработка приложений на языке C#. Полезные настройки. Особые спецификаторы формата, страница 44

·  Если текущий документ не выставлен на default-принтер, то переменная defaultPrinterName будет = "".

Замените рассмотренное выше словоблудие на код, приведенный ниже, и вы получите правильный результат, причем прочесть (и выполнить) его значительно проще. Вместо массы ненужных переменных (объявленных a la Pascal) введены новые, которые действительно повышают performance, так устраняют дублирование операций.

void ShowPrinters()

{

PrinterSettings setting = printDoc.PrinterSettings;

string docPrinter = setting.PrinterName,  info = "";

PrinterSettings.StringCollection printers = PrinterSettings.InstalledPrinters;

for (int i = 0;  i < printers.Count;  i++)

{

  setting.PrinterName = printers[i];    // По очереди примеряем  все принтеры

  info += printers[i]  +

    "\nIsValid = "     + setting.IsValid +

    "\nIsDefault = "   + (printers[i] == docPrinter).ToString() +

    "\nPrintToFile = " + setting.PrintToFile + "\n\n";

}

MessageBox.Show (info,"Printers");

}

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

while (CurrentLine < LinesPerPage)

{

TextLine = StreamToPrint.ReadLine();

if(TextLine == null)

{

  break;

}

// set the vertical position on the page based

// on the current line number

VerticalPosition = TopMargin + CurrentLine * MyFont.GetHeight(e.Graphics);

// draw the text on the page

e.Graphics.DrawString(TextLine, MyFont, MyBrush, HorizontalPosition, VerticalPosition);

// increment the line number

CurrentLine += 1;

}

Вопросы: CurrentLine — это переменная класса или локальная (временная)? TextLine — (очевидно) локальная переменная, но где она объявлена? Как долго живет? Где объявлены VerticalPosition и HorizontalPosition? Объектом какого класса является StreamToPrint? Похоже, что FileStream. Но у всех классов из иерархии Stream нет метода ReadLine! Оказалось, что это объект класса StremReader, то есть, почти из другой оперы. Теперь поразмыслим.

·  Вычислять в цикле то, что от него не зависит, — не только расточительство, но и признак лени или слабого ума (см. оператор: MyFont.GetHeight(e.Graphics). Он расположен внутри тела цикла).

·  Очевидное правило: выносите за цикл все, что можно из него вынести.

·  Если присутствует код подготовки к циклу и код, изменяющий переменные управления циклом (а они здесь присутствуют), то надо использовать цикл for (и только for). Все другие решения — плохой стиль.

·  Логика цикла должна быть ясна из его заголовка, каким бы сложным он не был (постулат Кернигана и Ритчи).

·  Если программист испытывает затруднения при анализе сложного заголовка цикла, ему надо тренироваться.

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

·  Все переменные должны использовать Camel-notation (начинаться со строчной буквы), иначе их трудно отличить от имен классов, особенно, в случае, если классы имеют статические данные или методы (см. MSDN).

·  Если можно обойтись без break, сделай это.

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

·  Временные переменные не должны требовать от вас усилий, их имена как бы говорят читателю: "Это — ерунда, жди результата". Наоборот, имена переменных класса должны нести смысл (printDoc, myFont и т.д.).

·  Большинство программистов заканчивали приличные ВУЗы и, поэтому, привыкли к математической нотации (i, j, k — временные индексы, n — number). Если переменная типа double живет недолго, ее смысл неважен — назовите ее d. Временную переменную типа float назовите коротко — f,

Новую версию фрагмента оформим в виде реакции на событие PrintPage компонента printDoc.