пятница, 30 мая 2008 г.

Смотрю в книгу – вижу буквы

Недавно нашел интересную статью Стива Макконелла «How To Read a Technical Article». Эту статью он написал 10 лет назад, когда занимал должность главного редактора в IEEE Software. Макконелл обобщает свой опыт чтения статей на компьютерную тематику и объясняет, как можно извлечь из статьи максимум пользы при лимите времени. Несмотря на то, что статья Макконелла прежде всего ориентирована на чтение статей в традиционных журналах, уверен, что его советы окажутся полезными и для статей блогосферы.

Он выделяет 4 типа чтения:
  • Базовый – распознавание отдельных слов. Приобретается, как правило, в детском саду. Название этой статьи характеризует данный стиль чтения.
  • Обзорное – более продвинутый уровень. Ориентирован на получение максимума информации за ограниченное время. Его еще называют «чтение по диагонали».
  • Аналитический – еще более продвинутый уровень. Извлечение максимума информации при неограниченном количестве времени.
  • Синтезирующий – самый крутой уровень. Получение информации из нескольких литературных источников, которой может и не быть в явном виде в каждом из них отдельно. Описание запутанное, но уровень обязывает :).
Начинать чтение Макконелл рекомендует с получения общей информации о статье: прочитать аннотацию, введение, заключение, название разделов статьи, затем прочитать статью по диагонали и, наконец, повторно прочитать заинтересовавшие разделы статьи – ещё более внимательно.

Также Макконелл рекомендует вступить в диалог с автором статьи и ответить на ряд вопросов, которые помогут понять статью лучше. Вот некоторые из них:
• О чем эта статья в целом?
• На чем автор хотел заострить внимание читателей?
• Не привирает ли автор в целом и в мелочах?
• Почему он пишет о A, а не о B?

P.S. В начале статьи я привел ссылку, где статью можно скачать совершенно бесплатно, а здесь ее предлагают купить за 19$ и вот что интересно: обе ссылки мне выдал Google и оба ресурса принадлежат IEEE Software. Странный бизнес.

вторник, 27 мая 2008 г.

Ложка меда в бочке дегтя

Недавно Сергей Розовик описывал неудобства связвнные с новым MSDN Magazine Online. Однако не все так плохо, есть и положительные мометны. Об одном из них я и хочу написать. Я не сам ее обнаружил :), об этой фиче написал в своем блоге Mike Stall.
Суть ее в том, что статью из MSDN для класса из BCL можно открыть по урлам такого вот вида:

http://msdn.microsoft.com/en-us/library/system.io.
filesystemwatcher
.aspx – для класса

http://msdn.microsoft.com/en-us/library/system.io.
filesystemwatcher.waitforchanged
.aspx – для метода класса

http://msdn.microsoft.com/en-us/library/system.io.
filesystemwatcher.path
.aspx – для свойства.

По моему, это очень удобно.

воскресенье, 25 мая 2008 г.

Моя любимая комбинация из трех пальцев

Нет, это не Ctr+Alt+Del, как некоторые могли подумать ;). Это – Ctrl+Shift+G. Уж больно часто в последнее время я использую эту команду. Она почему-то недокументированная и поэтому уверен, что многие о ней не знают. Это клавиатурное сочетание действует для комбобокса поиска, расположенного на панели инструментов Standard.


Если вы введете в этот комбобох имя файла (например, Class1.cs или app.config) и нажмете Ctrl+Shift+G, то команда пробежит по всем проектам открытого солюшена, найдет файл с таким именем и откроет его на редактирование. Эта функция существенно экономит время (и нервы) в случае сложных солюшенов с большим количеством проектов и файлов в них.

Я пользуюсь этой командой при анализе логов с исключениями, при поиске исходного текста типов, которые используются в конфигурационных файлах, для быстрого открытия файлов из разных проектов, когда могу предположить, как называется файл, но не помню (или не знаю), где он точно лежит.

P.S. Кстати, попасть на эту панель, не снимая рук с клавиатуры, можно клавишами Ctrl+/ (VS 2005 и старше) и Ctrl+D (VS 2003).

суббота, 24 мая 2008 г.

Делегаты и события

Как вы думаете, где подвох в нижеприведенном коде?

button1.Click += new EventHandler(new EventHandler(OnBtnClick));
button1.Click -= new EventHandler(new EventHandler(OnBtnClick));

С подобным кодом я недавно встретился при отладке. Разумеется, он был не в таком очевидном виде. Подписка/отписка методов была завуалирована использованием разных делегатов, но с одинаковой сигнатурой и цепочкой вызовов методов, где эти делегаты и передавались, а на отладку проблемы мной было потрачено несколько часов.

Итак, вернемся к примеру. Этот код компилируется без ошибок и предупреждений. Метод, подписанный на событие, вызывается при генерации события, а вот отписка от события не работает.

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

public object Target
public MethodInfo Method

Target – это ссылка на объект, которому принадлежит метод, передаваемый в конструктор делегата. Он может быть null, если подписывается статический метод.
Method – содержит ссылку на подписываемый метод. При обычной подписке метода на событие, пример которой приведен ниже,

button1.Click += new EventHandler (form.OnBtnClick);

свойство Target будет содержать ссылку на form, а свойство Method – ссылку на подписываемый метод OnBtnClick.

Для случая, когда при создании делегата ему передается другой делегат (как в исходном примере), свойство Target ссылается на передаваемый делегат, а Method содержит ссылку на метод Invoke, который генерируется для каждого делегата.

При отписке делегата от события, для которого вызывается статический метод Delegate.Remove, у делегатов (уже подписанного и используемого для отписки) вызывается метод Equals, чтобы убедиться что они обертывают собой один и тот же метод одного и того же объекта. У делегатов (классы Delegate и MulticastDelegate) операторы равенства и методы Equals перегружены (их код можно посмотреть, например, в Reflector). В методе Equals сравниваются свойства Target и Method, а операторы равенства вызывают Equals. Сравнение свойства Target выполняется оператором ==, а поскольку свойство Target имеет тип object, то вызывается оператор сравнения для object. Оператор == для object в свою очередь сравнивает значения ссылок (Reference Equals), которые для нашего примера очевидно не совпадают. Делегаты, подписанный и используемый для отписки, считаются разными и, как следствие, отписка метода не происходит.

Надеюсь, эта статья поможет вам сэкономить время при отладке подобного кода и избежать таких ловушек при написании собственного.