Ответ 1
Во-первых, ваше представление о том, что является ООП "фундаментальным", не является фундаментальным. Изобретатель термина "объектно-ориентированный", Алан Кей, классно сказал:
Я составил термин "объектно-ориентированный", и могу сказать, что у меня не было С++.
Конечно, идея о том, что лексически "все идет внутри класса", не является основополагающим принципом ООП. Мне даже не ясно, что идея "класса" имеет фундаментальное значение для объектно-ориентированного программирования; шаблон "наследование на основе класса" является всего лишь одним из способов внедрения в языковую поддержку таких понятий, как передача сообщений, абстракция данных и совместное использование.
Во-вторых, ваш вывод о том, что С# разработчики языка пытаются создать язык, который соответствует "основам" ООП, ставит телегу перед лошадью. Скорее, мы хотим создать язык, который поддерживает большие, разнообразные команды, работающие вместе над версиями, независимыми, взаимодействующими программными компонентами на наших платформах. ООП просто оказывается отличным способом сделать это, так что мы делаем.
Мы, конечно, не пытаемся сделать "чистый" язык ООП любым способом. Мы возьмем идеи из любой парадигмы, если они будут поддерживать реальные клиентоориентирующие сценарии. В С# есть идеи, взятые из ООП, от процедурного программирования, от функционального программирования, от динамических языков и т.д.
В-третьих, ваш вопрос логически непоследователен. Вы спрашиваете, почему вы можете определить делегат вне класса. Но делегат - это класс. Делегат - это особый класс; он всегда запечатан, он всегда наследуется от System.MulticastDelegate, и он всегда имеет одни и те же элементы. Но это класс. Мы придаем ему особый синтаксис, чтобы назвать, что это особый класс. Имеет смысл определить класс делегата вне класса.
В-четвертых, конечная причина, по которой законно размещать делегата вне класса, заключается в том, что это очень удобно. Каким классом вы считаете, что Func<T>
или EventHandler
должны войти внутрь? Будет ли этот класс "ООП" ? Согласно обычной мудрости "ООП" класс должен представлять собой концепцию путем сопоставления операций с данными; какой концептуальный класс вещей предлагает ваш предложенный родительский класс Func<T>
, и каковы операции и данные на нем?
Нет такого разумного внешнего класса, и нет никаких операций или данных, связанных с "внешним классом" Func<T>
. Итак, зачем заставлять пользователя определять бесполезный внешний класс, просто чтобы быть совместимым с кем-то ошибочным представлением о том, что означает "ООП" ?