Ранее обсуждался вопрос о переполнении стека, который мы должны предпочесть атрибутам интерфейсы маркеров (интерфейсы без каких-либо членов). статья о дизайне интерфейса в MSDN также подтверждает эту рекомендацию:
Избегайте использования интерфейсов маркеров (интерфейсы без элементов).
Пользовательские атрибуты предоставляют способ маркировки типа. Дополнительные сведения о настраиваемых атрибутах см. В разделе "Написание пользовательских атрибутов". Пользовательские атрибуты предпочтительнее, если вы можете отложить проверку атрибута до тех пор, пока код не будет выполнен. Если ваш сценарий требует проверки времени компиляции, вы не можете выполнить это руководство.
Там даже правило FxCop для обеспечения этой рекомендации:
Избегайте пустых интерфейсов
Интерфейсы определяют членов, которые предоставляют соглашение о поведении или использовании. Функциональность, описанная интерфейсом, может быть принята любым типом, независимо от того, где тип отображается в иерархии наследования. Тип реализует интерфейс, предоставляя реализации для членов интерфейса. Пустой интерфейс не определяет каких-либо членов и как таковой не определяет контракт, который может быть реализован.
Если ваш проект включает в себя пустые интерфейсы, которые, как предполагается, будут реализовываться, вы, вероятно, используете интерфейс в качестве маркера или способ идентификации группы типов. Если это идентификация произойдет во время выполнения, правильным способом добиться этого является использование настраиваемого атрибута. Используйте наличие или отсутствие атрибута или свойств атрибута для идентификации целевых типов. Если идентификация должна произойти во время компиляции, то использование пустого интерфейса приемлемо.
В статье указывается только одна причина, по которой вы можете игнорировать предупреждение: когда вам нужна идентификация времени компиляции для типов. (Это согласуется с конструкцией интерфейса).
Безопасно исключить предупреждение из этого правила, если интерфейс используется для идентификации набора типов во время компиляции.
Вот и возникает актуальный вопрос: Microsoft не соответствовала их собственной рекомендации в дизайне библиотеки классов Framework (по крайней мере, в нескольких случаях): Интерфейс IRequiresSessionState и Интерфейс IReadOnlySessionState. Эти интерфейсы используются инфраструктурой ASP.NET, чтобы проверить, должно ли оно включать состояние сеанса для конкретного обработчика или нет. Очевидно, что он не используется для идентификации времени типа компиляции. Почему они этого не сделали? Я могу думать о двух потенциальных причинах:
-
Микро-оптимизация: проверка того, реализует ли объект интерфейс (
obj is IReadOnlySessionState
), быстрее, чем использование отражения для проверки атрибута (type.IsDefined(typeof(SessionStateAttribute), true)
). Разница незначительна в большинстве случаев, но на самом деле это может иметь значение для критического кода производительности в среде выполнения ASP.NET. Однако есть обходные пути, которые они могли бы использовать как кеширование результата для каждого типа обработчика. Интересно, что веб-службы ASMX (которые подчиняются аналогичным характеристикам производительности) фактически используют свойствоEnableSession
WebMethod
атрибут для этой цели. -
Возможность реализации интерфейсов потенциально более вероятно будет поддерживаться, чем декорирование типов с помощью атрибутов сторонними .NET-языками. Поскольку ASP.NET разработан как агностический язык, а ASP.NET генерирует код для типов (возможно, на стороннем языке с помощью CodeDom), которые реализуют упомянутые интерфейсы на основе атрибута
EnableSessionState
директивы<%@ Page %>
, может возникнуть смысл использовать интерфейсы вместо атрибутов.
Каковы убедительные причины использования интерфейсов маркеров вместо атрибутов?
Это просто (преждевременная?) оптимизация или крошечная ошибка в дизайне структуры? (Думают ли они отражение - это "большой монстр с красными глазами" ?) Мысли?