Почему мы можем объявлять делегатов вне класса? Разве это не против концепции ООП?

Согласно основам oops, все должно быть внутри класса. Тогда почему нам разрешено создавать делегаты вне класса?

Ответ 1

Во-первых, ваше представление о том, что является ООП "фундаментальным", не является фундаментальным. Изобретатель термина "объектно-ориентированный", Алан Кей, классно сказал:

Я составил термин "объектно-ориентированный", и могу сказать, что у меня не было С++.

Конечно, идея о том, что лексически "все идет внутри класса", не является основополагающим принципом ООП. Мне даже не ясно, что идея "класса" имеет фундаментальное значение для объектно-ориентированного программирования; шаблон "наследование на основе класса" является всего лишь одним из способов внедрения в языковую поддержку таких понятий, как передача сообщений, абстракция данных и совместное использование.

Во-вторых, ваш вывод о том, что С# разработчики языка пытаются создать язык, который соответствует "основам" ООП, ставит телегу перед лошадью. Скорее, мы хотим создать язык, который поддерживает большие, разнообразные команды, работающие вместе над версиями, независимыми, взаимодействующими программными компонентами на наших платформах. ООП просто оказывается отличным способом сделать это, так что мы делаем.

Мы, конечно, не пытаемся сделать "чистый" язык ООП любым способом. Мы возьмем идеи из любой парадигмы, если они будут поддерживать реальные клиентоориентирующие сценарии. В С# есть идеи, взятые из ООП, от процедурного программирования, от функционального программирования, от динамических языков и т.д.

В-третьих, ваш вопрос логически непоследователен. Вы спрашиваете, почему вы можете определить делегат вне класса. Но делегат - это класс. Делегат - это особый класс; он всегда запечатан, он всегда наследуется от System.MulticastDelegate, и он всегда имеет одни и те же элементы. Но это класс. Мы придаем ему особый синтаксис, чтобы назвать, что это особый класс. Имеет смысл определить класс делегата вне класса.

В-четвертых, конечная причина, по которой законно размещать делегата вне класса, заключается в том, что это очень удобно. Каким классом вы считаете, что Func<T> или EventHandler должны войти внутрь? Будет ли этот класс "ООП" ? Согласно обычной мудрости "ООП" класс должен представлять собой концепцию путем сопоставления операций с данными; какой концептуальный класс вещей предлагает ваш предложенный родительский класс Func<T>, и каковы операции и данные на нем?

Нет такого разумного внешнего класса, и нет никаких операций или данных, связанных с "внешним классом" Func<T>. Итак, зачем заставлять пользователя определять бесполезный внешний класс, просто чтобы быть совместимым с кем-то ошибочным представлением о том, что означает "ООП" ?

Ответ 2

Фактически делегаты - это тип (класс). Это просто синтаксический сахар, если можно, когда вы объявляете делегата типа

public delegate int PerformCalculation(int x, int y);

Делегат - это тип, который безопасно инкапсулирует метод. Типы делегатов выводятся из класса Delegate в .NET Framework.

http://msdn.microsoft.com/en-us/library/ms173172%28v=vs.80%29.aspx

Итак, когда вы объявляете делегата вне класса, вы фактически создаете новый тип/класс. Затем вы создаете экземпляр делегата в классе.

С учетом сказанного, как замечает @Mehrdad, все должно быть внутри класса, не является обязательным для ООП.

Ответ 3

Это НЕ ООП "фундаментальный".

Это просто выбор языка на некоторых языках, таких как Java.

Объектно-ориентированное программирование просто означает моделировать проблему, используя объекты, называемые "объекты", которые имеют состояние и поведение. В нем ничего не говорится о том, куда должен идти ваш код.

Фактически вы можете создавать "объекты", даже не имея классов в первую очередь. Просто верните делегат, у которого есть закрытие, и у вас есть объект.

Пример:

//An "adder" that adds the value you give it to its current value
Converter<int, int> MakeAdder(int addend) //"constructor"
{
    return msg =>
    {
        addend += msg;
        return addend;
    };
}

//...
var adder = MakeAdder(100); //Now I have an adder object!
for (int i = 0; i < 10; i++)
    Console.WriteLine(adder(i));

Это полностью рядом с тем, что лямбда в С# является классом. Вы можете сделать что-то подобное на языке, таком как Scheme, где нет такой вещи, как "класс" или "объект", который существует фундаментально, только лямбды.

Ответ 4

С# - это язык с несколькими парадигмами, а не чистый объектно-ориентированный язык.

Ответ 5

Я также задавался этим вопросом раньше, но потом я понял причину его объявления непосредственно внутри пространства имен. Это связано с тем, что когда вы объявляете делегата, огромный массив для этого делегата создается в backgound.