Почему C# не позволяет не являющиеся членом функции как C++

Сначала:

Определите функцию, которую вы хотите выполнить следующим образом:

function alertWorld(){
  alert("Hello World");
}

Затем запланируйте ее выполнение с помощью метода setTimeout:

setTimeout(alertWorld,1000)

Обратите внимание на два Вещи

  • вторым аргументом является время в миллисекундах
  • . В качестве первого аргумента вы должны передать только имя (ссылку) функции без скобок
65
задан 4 revs, 4 users 93% 9 March 2015 в 16:36
поделиться

9 ответов

См. Это сообщение в блоге:

http://blogs.msdn.com/ericlippert/archive/2009/06/22/why-doesn-tc-implement-top-level- method.aspx

(...)

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

Я понимаю, что такой общий ответ, вероятно, не рассматривает конкретный вопрос.

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

Ограничивая тела методов всегда внутри структуры или класса, мы упрощаем рассуждение о значении неквалифицированного идентификатора, используемого в контексте вызова; такая вещь всегда является вызываемым членом текущего типа (или базового типа).

(...)

и следующая запись:

http://blogs.msdn.com/ericlippert/archive/2009/06/24/it-already-is-a-scripting -language.aspx

(... )

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

(выделение из исходного текста)

86
ответ дан 24 November 2019 в 15:18
поделиться

Since Java, most programmers have easily accepted that any method is a member of a class. I doesn't make any considerable obstacles and make the concept of method more narrow, which make a language easier.

However, indeed, class infers object, and object infers state, so the concept of class containing only static methods looks a little absurd.

2
ответ дан 24 November 2019 в 15:18
поделиться

Я думаю, вам действительно нужно уточнить, для чего вы хотите создать статические методы, не являющиеся членами.

Например, некоторые вещи, для которых они могут понадобиться, могут быть решены с помощью Методы расширения

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

Кроме того, вам не обязательно сравнивать объектную модель C ++ с C #. C ++ в значительной степени (но не идеально) совместим с C, в котором вообще не было системы классов, поэтому C ++ должен был поддерживать эту идиому программирования из наследия C, а не для каких-либо конкретных требований дизайна.

1
ответ дан 24 November 2019 в 15:18
поделиться

Имейте в виду: C ++ - гораздо более сложный язык, чем C #. И хотя они могут быть похожи синтаксически, семантически они очень разные звери. Вы бы не подумали, что такое изменение будет ужасно сложно, но я видел, как это могло быть. У ANTLR есть хорошая вики-страница под названием Что делает языковую проблему сложной? , с которой можно проконсультироваться по таким вопросам. В данном случае:

Контекстно-зависимый лексер? Вы не можете решить, какому символу словаря соответствовать, если не знаете, какое предложение вы анализируете.

Теперь вместо того, чтобы беспокоиться о функциях, определенных в классах, мы должны беспокоиться о функциях, определенных вне классов. Концептуально большой разницы нет. Но с точки зрения лексирования и синтаксического анализа кода, теперь у вас есть дополнительная проблема: «если функция находится вне класса, она принадлежит этому безымянному классу. Однако, если она находится внутри класса, то она принадлежит этому классу».

Кроме того, если функция компилятор сталкивается с таким методом:

public void Foo()
{
    Bar();
}

... теперь он должен ответить на вопрос: «Бар находится внутри этого класса или это глобальный класс?»

Прямые или внешние ссылки? Т.е. нужно несколько проходов? В Паскале есть «прямая» ссылка для обработки внутрифайловых ссылок на процедуры, но ссылки на процедуры в других файлах через предложения USES и т. Д. Требуют специальной обработки.

Это еще одна вещь, которая вызывает проблемы. Помните, что C # не требует предварительных объявлений. Компилятор сделает один проход, чтобы определить, какие классы названы и какие функции содержат эти классы. Теперь вам нужно позаботиться о нахождении классов и функций, в которых функции могут находиться как внутри, так и вне класса. Это то, о чем синтаксическому анализатору C ++ не нужно беспокоиться, поскольку он разбирает все по порядку.

Не поймите меня неправильно, это, вероятно, можно было бы сделать на C #, и я бы, вероятно, использовал такую ​​возможность. Но действительно ли стоит тратить силы на преодоление этих препятствий, если можно просто ввести имя класса перед статическим методом?

1
ответ дан 24 November 2019 в 15:18
поделиться

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

Возможно, в будущей версии C # будет добавлена ​​возможность писать директиву using , которая позволяет получить доступ к статическим членам класса без уточнения имени класса:

using System.Linq.Enumerable; // Enumerable is a static class

...

IEnumerable<int> range = Range(1, 10); // finds Enumerable.Range

Тогда не будет необходимости изменять CLS и существующие библиотеки.

Эти сообщения в блоге демонстрируют библиотеку для функционального программирования на C # , и они используют имя класса, состоящее из одной буквы, чтобы попытаться уменьшить шум, вызванный требованием квалифицировать вызовы статических методов.

3
ответ дан 24 November 2019 в 15:18
поделиться

Функции, не являющиеся членами, - это хорошо , потому что они улучшают инкапсуляцию и уменьшают связь между типами. Большинство современных языков программирования, таких как Haskell и F #, поддерживают бесплатные функции.

12
ответ дан 24 November 2019 в 15:18
поделиться

В чем преимущество , а не помещения каждого метода в именованный класс? Почему функция, не являющаяся членом, «загрязняет» интерфейс класса? Если вы не хотите, чтобы он был частью общедоступного API класса, либо не публикуйте его, либо не помещайте в этот класс. Вы всегда можете создать другой класс.

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

Короче говоря, я не вижу никаких преимуществ в функциях, не являющихся членами, но я вижу преимущества с точки зрения согласованности, именования и документации при помещении всех методов в класс с соответствующим именем.

9
ответ дан 24 November 2019 в 15:18
поделиться
  • Размещение всего кода внутри классов позволяет использовать более мощный набор возможностей отражения.
  • Он позволяет использовать статические инициализаторы, которые могут инициализировать данные, необходимые для статических методов внутри класса.
  • Он позволяет избежать конфликтов имен между методами, явно заключая их в модуль, который не может быть добавлен другим модулем компиляции.
3
ответ дан 24 November 2019 в 15:18
поделиться

C # не допускает этого, потому что Java этого не допускает.

Я могу придумать несколько причин, по которым разработчики Java, вероятно, не допустили этого.

  • Java была разработана как простая. Они попытались создать язык без случайных сокращений, так что у вас обычно есть только один простой способ сделать все, даже если другие подходы были бы более понятными или более краткими. Они хотели минимизировать кривую обучения, а изучение «класс может содержать методы» проще, чем «класс может содержать методы, а функции могут существовать вне классов».
  • На первый взгляд это выглядит менее объектно-ориентированным. (Все, что не является частью объекта, очевидно, не может быть объектно-ориентированным? Может ли? Конечно, C ++ говорит «да», но C ++ не участвовал в этом решении)

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

В C ++, где разрешены функции, не являющиеся членами, они часто предпочтительны по нескольким причинам:

  • Это помогает инкапсуляция. Чем меньше методов имеет доступ к закрытым членам класса, тем проще будет рефакторинг или обслуживание этого класса. Инкапсуляция - важная часть ООП.
  • Код гораздо проще использовать повторно, если он не является частью класса. Например, стандартная библиотека C ++ определяет std :: find или std :: sort` как функции, не являющиеся членами, поэтому их можно повторно использовать в любом типе последовательностей, будь то массивы, наборы, связанные списки или (по крайней мере, для std :: find) потоки. Повторное использование кода также является важной частью ООП.
  • Это дает нам лучшую развязку. Функция find не должна знать о классе LinkedList, чтобы иметь возможность работать с ним. Если бы он был определен как функция-член, он был бы членом класса LinkedList, в основном объединяя две концепции в один большой blob.
  • Расширяемость. Если вы согласны с тем, что интерфейс класса - это не только «все его общедоступные члены», но также «все функции, не являющиеся членами, которые работают с классом», тогда становится возможным расширить интерфейс класса без необходимости редактирования или даже перекомпилируйте сам класс.

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

Фактически, C #, похоже, реализовал почти то же самое гораздо позже. Как вы думаете, почему были добавлены методы расширения? Они представляют собой попытку достичь вышеуказанного при сохранении простого синтаксиса, подобного Java. Лямбды также являются интересными примерами, поскольку они тоже по сути небольшие функции, определяемые свободно, а не как члены какого-либо конкретного класса. Так что да, концепция функций, не являющихся членами, полезна, и дизайнеры C # осознали то же самое. Они только что попытались внедрить концепцию через черный ход.

http://www.ddj.com/cpp/184401197 и http://www.gotw.ca/publications/ mill02.htm - две статьи, написанные экспертами по C ++ по этой теме.

39
ответ дан 24 November 2019 в 15:18
поделиться
Другие вопросы по тегам:

Похожие вопросы: