Почему «использование системы»; не считается плохой практикой?

47

У меня есть опыт работы с C ++, и я полностью понимаю и согласен с ответами на этот вопрос: почему «используется пространство имен std;» считается плохой практикой?

Поэтому я удивлен тем, что, имея некоторый опыт работы с C # сейчас, я вижу здесь совершенно противоположное: using Some.Namespace;буквально используется везде. Всякий раз, когда вы начинаете использовать тип, вы сначала добавляете директиву using для его пространства имен (если его там еще нет). Я не могу вспомнить, чтобы я видел .csфайл, который не начинался с using System; using System.Collections.Generic; using X.Y.Z; etc.... Фактически, если вы добавляете новый файл с помощью мастера Visual Studio, он автоматически добавляет туда некоторые директивы using, даже если они вам вообще не нужны. Итак, в то время как в сообществе C ++ вас в основном линчуют, C # даже поощряет это делать. По крайней мере, так мне кажется.

Теперь я понимаю, что использование директив в C # и C ++ - это не одно и то же. Кроме того, я понимаю, что одна из самых неприятных вещей, которые вы можете сделать using namespaceв C ++, а именно, поместить ее в файл заголовка, не имеет такого же неприятного аналога в C # из-за отсутствия концепции файлов заголовков и #include.

Однако, несмотря на их различия, использование директив в C # и C ++ служит одной и той же цели, которая заключается только в том, чтобы печатать SomeTypeвсе время, а не намного дольше Some.Namespace.SomeType(в C ++ ::вместо вместо .). И с этой же целью мне кажется, что опасность та же: называть коллизии.

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

Некоторые идеи ответа, который у меня есть (но ни один из них действительно не удовлетворяет меня):

  • Пространства имен, как правило, намного длиннее и гораздо больше вложены в C #, чем в C ++ ( stdпротив System.Collection.Generic). Таким образом, есть больше желания и больше выгоды в устранении шума в коде таким образом. Но даже если это правда, этот аргумент применяется только тогда, когда мы смотрим на стандартные пространства имен. Пользовательские могут иметь любое короткое имя на C # и C ++.

  • Пространства имен кажутся гораздо более «тонкими» в C #, чем в C ++. Например, в C ++ вся стандартная библиотека содержится в std(плюс несколько крошечных вложенных пространств имен, например chrono), в то время как в C # у вас есть System.IO, System.Threadingи System.Textт. Д. Таким образом, риск возникновения коллизий именования меньше. Тем не менее, это только внутреннее чувство. На самом деле я не посчитал, сколько имен вы «импортируете» с помощью using namespace stdи using System. И снова, даже если это так, этот аргумент применяется только при рассмотрении стандартных пространств имен. Ваши собственные могут быть спроектированы так, как вы хотите, на C # и C ++.

Есть ли еще аргументы? Я особенно заинтересован в реальных фактах (если они есть), а не во мнениях.

sebrockm
источник
2
@Timo ОП явно не спрашивает о загрязнении заголовка.
Конрад Рудольф
1
Я предположил, что это потому, что нет конкуренции за глобальное пространство имен в той же степени, что и в C ++ (в основном из-за стандартной библиотеки C). Но я жду ответов тех, кто знает лучше.
Вик
2
@ThomasWeller В C ++ это очевидно. В C # рассмотрим метод расширений, Ext(this T t, long l)который вызывается через t.Ext(0). Если затем вы добавите другое пространство имен, содержащее метод расширения Ext(this T t, int i), оно будет вызываться вместо этого. Но я не эксперт в C # (пока).
sebrockm
2
@ Фрэнк, даже если я предоставил вам эту точку зрения, то тот же аргумент применим к C ++, что еще больше подтолкнуло меня к вопросу о том, что я не вижу различия между C ++ и C #
sebrockm
3
@Franck C ++ выдаст вам ошибку компилятора в случае неоднозначности. Как и C #.
Тимо

Ответы:

28

Почему «использование системы»; не считается плохой практикой?

"используя Систему"; это не универсально не считается плохой практикой. Смотрите, например: Почему бы вам не использовать директиву using в C #?

Но это может быть правдой, что это не так плохо, как using namespace std. Вероятно потому что:

  1. C # не имеет заголовочных файлов. Нередко «включать» один исходный файл C # в другой, используя препроцессор.

  2. stdпространство имен почти плоское, т. е. почти все стандартные библиотечные функции, типы и переменные находятся в нем (есть несколько исключений, таких как подпространство имен файловой системы). Он содержит очень и очень большое количество идентификаторов. Насколько я понимаю, System содержит гораздо меньше имен и вместо этого имеет больше подпространств имен.

  3. В C # нет глобальных функций или переменных. Таким образом, число глобальных идентификаторов, как правило, довольно мало в отличие от C ++, который имеет такие: Кроме того, типично использовать библиотеки C (часто косвенные), которые не имеют пространств имен, и, следовательно, помещать все их имена в глобальные. Пространство имен.

  4. Насколько я знаю, C # не имеет зависимого от аргумента поиска. ADL в сочетании с сокрытием имени, перегрузкой и т. Д. Может привести к случаям, когда некоторые программы не затронуты конфликтом имен, в то время как другие незаметно затронуты, и выявление всех угловых случаев невозможно при тестировании.

Из-за этих различий «использование системы»; имеет более низкий шанс конфликта имен, чемusing namespace std .


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

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

eerorika
источник
3
Это учитывает только потенциальные недостатки открытия пространств имен. Это начало, но я думаю, что мы также должны рассмотреть преимущества: в случае C ++ в большинстве случаев сохраняется пять символов ( std::). В C # это значительно больше ( System.имеет «всего» 7 символов, но другие, вложенные пространства имен имеют гораздо больше символов, и их выписывание везде сделает код полностью нечитаемым).
Конрад Рудольф
Разве это не тот случай, когда разрешение перегрузки в C # более доброе, чем в C ++, и большая неопределенность вытягивается из-за ошибок компилятора? (Ни в коем случае не критика вашего ответа, который кажется авторитетным.)
Вирсавия
3
@KonradRudolph Если бы недостатки считались значительными, и количество печатаний одинаково (по сравнению с количеством печатаний std::), разве не было бы типичным стилем использовать using Sys = System;вместо пространства имен загрязняющие псевдонимы using?
eerorika
2
@Bathsheba относительно "авторитетного", я хотел бы отрицать, что я очень мало знаю о C #, и мой ответ основан на знании C ++ и нескольких поисках Google о C #. Так что я был бы признателен, если бы кто-то проверял детали C # :)
eerorika
2
Что касается части ADL: C # имеет методы расширения. Это другой дизайн, чем ADL, но они имеют те же проблемы, что и конфликты имен.
Тимо
-2

Однако, несмотря на их различия, использование директив в C # и C ++ служит одной и той же цели, которая заключается только в том, чтобы постоянно вводить SomeType, а не в более длинный Some.Namespace.SomeType (в C ++ с :: вместо.). И с этой же целью мне также угрожает опасность: называть коллизии.

Да, но вы не экспортировали эту опасность (читай: заставлять других справляться с ней) из-за:

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

Так что это скорее другая категория вещей.

Кроме того, C ++ не «предназначен» для разработки в IDE так же, как C #. C # в основном всегда написан в Visual Studio с его Intellisense и еще много чего. Он создан для того, чтобы его использовали люди, которые его создали. Независимо от того, сколько людей используют IDE для разработки на C ++, она не предназначена для этого варианта использования как непреодолимая проблема.

Пространства имен кажутся гораздо более «тонкими» в C #, чем в C ++.

Да, это тоже. using namespace stdи using System.Collection.Genericнесравненные.

Так что не сравнивайте их!

Астероиды с крыльями
источник
2
Это не отвечает озабоченности OP, которая явно касается не открытия пространств имен в заголовках, а в файлах реализации .
Конрад Рудольф
2
@KonradRudolph Советы, которых следует избегать using namespace stdв C ++, в основном касаются заголовочных файлов. Ответ в том, что это не относится к C #.
Астероиды с крыльями
8
@AsteroidsWithWings совет, которого следует избегать, using namespace stdв основном не касается заголовков. Использование его в заголовках опасно. Использование его в ваших реализациях не рекомендуется.
Томми Андерсен
1
Совет, которого следует избегать using namespace ...в c ++, состоит в том, чтобы избегать коллизий именования, usingдиректива в C # также вводит возможность коллизии имен, тогда почему бы не избежать ее? Хотя там реализация отличается.
Томми Андерсен
@ TommyAndersen, насколько сложно разрешить такой конфликт, если он случится? Это займет секунду. Поскольку usingобъявления C # относятся к файлу, который определяет один тип / класс, и тип обычно имеет отношение к относительно узкому набору концепций предметной области (в идеале, принципу единой ответственности), вероятность таких конфликтов пространства имен чрезвычайно низка. Но когда это происходит, это легко исправить. Общие инструменты разработки .NET / IDE помогут вам в этом. Рассмотрим всю экосистему разработки, которая разработана для того, чтобы сделать вас более продуктивным, сочетая лучшие из множества видов деятельности по разработке
AKornich