Пространство имен C # и соглашение об именах классов для библиотек

26

Я создаю библиотеки с различными небольшими служебными функциями в C # и пытаюсь принять решение относительно именования пространств и классов. Моя текущая организация выглядит так:

Company
Company.TextUtils
    public class TextUtils {...}
Company.MathsUtils
    public class MathsUtils {...}
    public class ArbitraryPrecisionNumber {...}
    public class MathsNotation {...}
Company.SIUnits
    public enum SISuffixes {...}
    public class SIUnits {...}

Это хороший способ организовать пространство имен и классы, или есть лучший способ? В частности, кажется, что наличие одного и того же имени в пространстве имен и имени класса (например, Company.TextUtilsпространства имен и TextUtilsкласса) является просто дублированием и предполагает, что схема могла бы быть лучше.

пользователь
источник
5
В руководящих принципах Microsoft рекомендуются единственные имена для перечислений (поэтому SISuffixвместо SISuffixes), и я думаю, что единственное число читается лучше. Suffix.A читается как «суффикс А». Кроме того, я вообще избегаю повторения имен с уровня в иерархии. То есть вместо того Company.SIUnits.SISuffixes, чтобы я склонялся Company.SI.SuffixиCompany.SI.Unit
Харрисон Пейн
2
@richzilla thecodelesscode.com/case/220
Tin Man

Ответы:

9

Очень трудно определить, насколько эффективна ваша стратегия именования в отрыве от остального кода.

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

Не будем обращать внимания, в вашем конкретном примере, если у вас, вероятно, будет гораздо больше классов типа «Util», я бы подумал о их размещении Company.Utils.Mathsи т. Д. Таким образом, если вам нужно добавить функциональность, которая является общей для нескольких служебных областей, вы уже естественное место для этого.

richzilla
источник
1
Это звучит как хорошая идея. Перестаньте слишком беспокоиться, просто добавьте все это в "Company.Util".
пользователь
30

Есть хороший документ, который содержит множество правил, которым вы должны следовать, чтобы соответствовать Microsoft: Framework Design Guidelines .

Одна вещь, которую вы должны изменить: не называйте классы как их пространство имен. Это приведет к путанице компилятора. Просто не надо. Найдите лучшее имя для класса пространства имен.

nvoigt
источник
3
Прямая ссылка на рекомендации по пространствам имен: msdn.microsoft.com/en-us/library/ms229026(v=vs.110).aspx
Паготти
1
По совпадению или нет, это тоже одно и то же название великой книги по этому вопросу, также написанной людьми Microsoft, которые участвовали в создании инфраструктуры DotNet, с несколькими замечаниями о том, что они сделали правильно и где у них что-то не так. Стоит прочитать: amazon.com/Framework-Design-Guidelines-Conventions-Libraries/dp/…
Мачадо
@nvoigt, не могли бы вы отредактировать свой ответ, добавив цитату из ссылки, предоставленной нашим другом Паготти: « НЕ используйте одно и то же имя для пространства имен и тип в этом пространстве имен. Например, не используйте Debug в качестве имени пространства имен и затем также предоставьте класс с именем Debug в том же пространстве имен. Несколько компиляторов требуют, чтобы такие типы были полностью квалифицированы ».
Мачадо
2
Предостережение: иногда название продукта лучше, чем использование названия компании. Было несколько сценариев, когда компания была выкуплена, и нам пришлось создавать новые пространства имен по всем направлениям и переиздавать. Я думаю, что это очень незначительно, но хотел указать на это.
Джон Рейнор
1
Рекомендации Microsoft по разработке каркасов очень сомнительны, содержат ложные утверждения о том, как работает .NET, и очень часто за ними не следит сама Microsoft. Их правила именования хороши, но я бы не стал связывать общие правила с утверждением, что «вы должны следовать» им.
Карл Лет
6

Прошло много времени с тех пор, как я работал с C # или экосистемой .NET, поэтому я не могу сказать, каковы текущие рекомендуемые рекомендации. Я бы порекомендовал изменить ваши имена, как это:

Company
Company.Text
    public class TextUtils {...}
Company.Math
    public class MathUtils {...}
    public class ArbitraryPrecisionNumber {...}
    public class MathsNotation {...}
Company.SI
    public enum SISuffixes {...}
    public class SIUnits {...}

То, что я сделал здесь, это удалил «Utils» из имен пространства имен. Я думаю, что «Util» не должен быть в пространстве имен, потому что Company.Textпространство имен может однажды содержать классы, которые не являются текстовыми служебными классами. Пространство Company.Mathимен уже содержит то, ArbitraryPrecisionNumberчто не похоже на «утилиту».

Удаление «Util» из пространства имен также устраняет любую путаницу, которая может возникнуть из-за наличия двух вещей с одинаковыми именами (как упоминалось в ответе Роберта: /software//a/340440/13156 )

Другой способ, которым вы могли бы организовать код:

Company
Company.Util
    public class TextUtils {...}
    public class MathUtils {...}
Company.Math
    public class ArbitraryPrecisionNumber {...}
    public class MathsNotation {...}
Company.SI
    public enum SISuffixes {...}
    public class SIUnits {...}

В этом случае все служебные классы находятся в одном пространстве имен. Company.TextПространства имен больше нет, поскольку единственное, что было, это служебный класс.

Лично я считаю первый вариант более понятным.

FrustratedWithFormsDesigner
источник
4

Использование одного и того же имени для пространства имен и класса внутри него проблематично.

  • Если пространство имен содержит более одного класса, почему другие классы будут помещены туда? это не кажется правильным, потому что цель имени пространства имен состоит в том, чтобы описать все классы в нем, а не только один. Например, если у вас есть JsonSerialization, BinarySerializationи XmlSerializationклассы в пространстве имен, будет ли смысл называть пространство имен XmlSerialization?

    Обычно происходит то, что из-за извлечения класса из существующего пространства имен или слияния нескольких классов или другой реорганизации вы попадаете в пространство имен, содержащее основной класс; постепенно, второстепенные классы помещаются туда, потому что они немного связаны с исходным классом. Например, пространство имен LogParserможет содержать один класс LogParser, а затем кто-то помещает его LogConverter, потому что оно весьма связано с анализатором, затем LogSearcherи т. Д. Проблема здесь в том, что имя пространства имен не изменилось: как только оно LogConverterбыло добавлено, имя должно быть изменено LogsProcessingили просто Logs.

  • Если пространство имен содержит только один класс, это может быть признаком проблемы в организации кода.

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

    Даже если ваше пространство имен содержит только один класс, обычно есть способ быть более конкретным при именовании класса и более общим при именовании пространства имен. Представьте себе приложение, которое, помимо прочего, должно в данный момент преобразовывать файлы, записанные в формате ABC, в формат DEF. Преобразование не требует какой-либо десериализации / сериализации в / из бизнес-объектов и выполняется путем применения набора регулярных выражений, которые достаточно коротки, чтобы помещаться в сам класс преобразования, называемыйAbcToDefConverter, Вся логика преобразования занимает около 80 LLOC примерно в десяти взаимозависимых методах - кажется, что в этой ситуации абсолютно нет необходимости ни делить существующий класс, ни создавать дополнительные классы. Поскольку остальная часть приложения не имеет ничего общего с преобразованиями, класс нельзя сгруппировать с другими классами в существующих пространствах имен. Таким образом, создается пространство имен AbcToDefConverter. Хотя в этом нет ничего неправильного, можно также использовать более общее имя, например Converters. В таких языках, как Python, где более короткие имена предпочтительнее и повторяется, это может даже стать converters.Abc_To_Def.

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


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

Именование существует по причине: чтобы сделать вашу жизнь проще, когда вам нужно найти вещи позже. Вы знаете, что если вам нужно нарисовать график, вы можете попытаться найти «график» или «график». Когда вам нужно изменить способ, которым приложение генерирует счета, вы будете искать «invoic [e / ing]» или «bill». Точно так же попробуйте представить себе случай, когда вы скажете себе: «Хм, эта функция, вероятно, должна быть найдена в misc». Я не могу

Посмотрите на .NET Framework. Разве большинство этих классов не являются служебными классами? Я имею в виду, они имеют мало общего с бизнес-доменом. Если я работаю над финансовым приложением, или веб-сайтом электронной коммерции, или образовательной платформой следующего поколения, сериализация XML или чтение файлов, выполнение запросов SQL или выполнение транзакций - все это полезные вещи. Тем не менее, они не называются UtilitySerializationили UtilityTransaction, и они не находятся в Utilityпространстве имен. У них есть собственные имена, которые позволяют (и легко, спасибо разработчикам .NET!) Найти их, когда они мне нужны.

То же самое касается ваших классов, которые вы обычно используете в своих приложениях. Они не являются служебными классами. Это классы, которые делают определенные вещи, и вещи, которые они делают, должны быть именами классов.

Представьте, что вы создали некоторый код, который имеет дело с единицами и преобразованием единиц. Вы можете назвать это Utilityи быть ненавидимыми вашими коллегами; или вы можете назвать это Unitsи UnitsConversion.

Арсений Мурзенко
источник
7
«Утилиты неправильны по своей природе». Интересный. Какое решение вы предлагаете для чего-то такого, как класс полезности функции Math? Должен ли экземпляр объекта Math действительно быть необходим для использования функций, выходящих за рамки основных арифметических операторов?
FrustratedWithFormsDesigner
1
Я согласен с вами, но что вы предлагаете в качестве альтернативы?
пользователь
4
Я откладывал создание библиотеки «utils» на долгое время, но в конечном итоге вам просто нужно сдаться. Альтернативой является наличие библиотек DLL, состоящих из примерно 3 строк кода, что просто громоздко (и напоминает мне о беспорядке зависимостей. Node.js ) или копирование и вставка ваших служебных методов в каждый отдельный класс, который может им понадобиться (чтобы не было этого класса «коллекции случайных методов»). ИМО в конце концов это неизбежное зло.
Матти Вирккунен
3
@FrustratedWithFormsDesigner: просто ... Math? Я не понимаю, как добавление Utilityсуффикса ко всему облегчит нашу жизнь. При использовании System.Math.Min()метода .NET вы бы предпочли писать SystemUtility.MathUtility.Min()? Во всех случаях я сильно отредактировал свой ответ, поэтому теперь он должен быть понятнее.
Арсений Мурзенко