Декларативный интерфейс
Для большинства небольших программ на WinForms отлично подходит дизайнер меню и панелей инструментов. Самый подходящий случай — это небольшая монолитная программка с более-менее фиксированным набором функций. Например, какой-нибудь простой текстовый редактор.
А самый неподходящий вариант — модульная программа, построенная на плагинах. Что если плагин должен иметь возможность добавлять команды в главное меню или кнопки на панель инструментов? Давать плагину доступ к меню небезопасно, поэтому обычно поступают наоборот: программа спрашивает у плагина, какие команды он поддерживает и сама добавляет их в свое меню. Для этого плагин должен поддерживать метод типа GetPluginCommands(), возвращающий коллекцию доступных команд.
В результате в плагине приходится писать здоровенный такой метод, который формирует некую древовидную структуру команд. При добавлении в плагин новых функций нужно каждый раз лезть в этот метод и что-то туда дописывать. В .NET есть гораздо более изящный вариант решения подобной задачи — с помощью атрибутов.
Посмотрите на картинку: панель инструментов и меню описываются атрибутами ToolButton и MenuItem. Чтобы добавить новую команду-кнопку на панель инструментов, я пишу метод-обработчик, реализующий эту команду, и помечаю его атрибутом [ToolButton("Название команды")]. Добавление команд в главное меню сделано почти так же, только атрибут MenuItem позволяет указывать полный путь для добавляемой команды. Например, пункт File -> Exit описывается атрибутом [MenuItem("File", "Exit")]. Уровень вложенности может быть любой. При старте программа строит список помеченных атрибутами методов и добавляет пункты в меню и кнопки на панель инструментов.
Чем такой подход хорош? Во-первых, при добавлении новых функций не нужно лезть в дизайнер, чтобы что-нибудь там найти. Во-вторых, команды можно вытаскивать из любого класса (из самой программы или из плагинов) совершенно одинаковым способом. Плагину не нужен будет монструозный метод GetPluginCommands(), не несущий никакой полезной нагрузки.
Мне очень нравится такое описание интерфейсов, по-моему, оно удобно даже в маленьких проектах вроде Exepack.NET. Я далеко не всегда пишу в VisualStudio, и дизайнер форм иногда запустить просто негде, так что этот способ меня здорово выручает.