Соглашение об именовании

Введение

Данное соглашение было разработано после тщательного изучения вопроса, прочтения множества оригинальной документации, в частности MSDN, книга Framework Design Guidelines, после обсуждения на форумах, и с разработчиками .Net платформы.

Это самое актуальное и современное соглашение на 2020 год. Главная цель соглашения - создать единый стиль наименования, который будет понятен всем разработчикам, вне зависимости от языка программирования. В том числе, облегчая портирование кода. Так же это важный аспект стандартизации в любой организации.

Обратите внимание, соглашение создавалось в первую очередь для языка C#, .Net и Unity. Но вы также можете применять его в других языках, где это возможно.

При написании имен идентификаторов используется два стиля:

  • PascalCasing - первая буква прописная
  • camelCasing - первая буква строчная

Основные правила

  • Публичные поля и свойства (включая static и readonly) пишутся по правилам PascalCasing:
    public DateTime                 Date;
    
    public int                      DayOfYear => GetDatePart(1);
    
    public static readonly Color    Black = new Color(0, 0, 0);
    
  • Приватные поля (включая static и readonly) пишутся по правилам camelCasing с добавлением префикса «_» (почему так?):
    [SerializeField]
    private Text      	_label;
    
    private bool            _pressed;
    
    private readonly int 	_x;
    
  • Параметры и локальные переменные пишутся по правилам camelCasing:
    public long DateToTicks(int year, int month, int day)
    {
       int index = 0;	  
    }
    
  • Интерфейсы пишутся по правилам PascalCasing, с добавлением префикса "I" (Interface):
    public interface IComparable
    {
    }
    
  • Данное правило относится как к публичным, так и к приватным модификаторам доступа. Типы (классы, структуры...), пространство имен, методы, события, константы, перечисления пишутся по правилам PascalCasing:
    private const int DaysPerYear = 365;
    
    public struct DateTime
    {
    }
    
    public static class Convert
    {
    }
    
    private enum DayOfWeek
    {
        Sunday,
        Monday,
        ..
    }
    
    public int CompareTo(object value)
    {
    }
    
    public event SampleEventHandler SampleEvent;
    

Дополнительные правила

  • Не используйте сокращения (кроме общеизвестных):
    // не правильно
    int UsrInd;
    int WepView;
    int EffStyle;
    
    // правильно
    int UserIndex;
    int WeaponView;
    int EffectStyle;
    
    Если у вас в одном классе становится слишком много полей, и вам приходится добавлять префиксы, подумайте об разделении на несколько классов по логике и функционалу.
  • Используйте латинские буквы и существующие слова, не пишите транслитом:
    // не правильно
    public object Stena;
    public object Zabor;
    
    // правильно
    public object Wall;
    public object Fence;
    
    Eсли у вас плохо с английским языком, всегда может помочь переводчик этот или этот.
  • Используйте легко читаемые и грамматически правильные имена:
    // не правильно
    public object ContentGet() 
    
    // правильно
    public object GetContent() 
    
  • Не пишите тип в имени идентификатора:
    // не правильно
    private string _strTitle;
    private int _intDay;
    
    // правильно
    private string _title;
    private int _day;
    
  • Избегайте числа в именах идентификаторов:
    // не правильно
    public object Wall1;
    public object Wall2;
    public object Wall3;
    
    // правильно
    public object WallStone;
    public object WallWood;
    public object WallMetal;
    
    Чаще всего, использование чисел в именах идентификаторов говорит о нежелании придумывать нормальные имена.

Примечание

  • Почему приватные поля пишутся с префиксом "_" ?

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

    Использование стиля camelCasing без префикса:
    1. новый современный вид без каких-либо префиксов:
      int index;
      int id;
      Data data;
      
    Использование стиля camelCasing с префиксом «_»:
    1. Визуально глаз моментально определяет, что это - приватное поле, нежели пытается разглядеть регистр первой буквы
    2. При сортировке полей и свойств по алфавиту поля с префиксом «_» всегда будут в самом начале
    3. При переносе кода в регистронезависимый язык у вас не будет проблем:
      // index = Index, проблемы будут
      private int index;
      public int Index => index;
      
      // _index != Index, проблем не будет
      private int _index;
      public int Index => _index;
      
    4. Исключение коллизий имен полей и параметров:
      private float x;
      private float y;
      class MyClass
      {
          public MyClass(float x, float y)
          {
              // вам придется использовать this (в данном случаи это избыточно), т.к. имена полей совпадают с именами параметров
              this.x = x;
              this.y = y;
          }
      }
      
      // при использовании префикса "_", такой проблемы у вас не будет
      private float _x;
      private float _y;
      class MyClass
      {
          public MyClass(float x, float y)
          {
              _x = x;
              _y = y;
          }
      }
                          
    5. Мы не нарушаем правило CA1500, так как у нас априори имена полей не могут совпадать с именами параметров
    6. На сегодняшний день такому стилю придерживаются разработчики dotnet/runtime

Примеры

Различные классы, не связанные друг с другом.

  • using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    using UnityEngine.UI;
    
    namespace Mim.Translation.UI
    {
    
        [AddComponentMenu("Mim/Translation/Translate Text")]
        [RequireComponent(typeof(Text))]
        public class TranslateText : MonoBehaviour
        {
    
            #region Fields
    
            [SerializeField]
            private Text    _field;
    
            [SerializeField]
            private int     _index;
    
            #endregion
    
            #region Methods
    
            private void Start() => _field.text = Translation.TableUI[_index];
    
    #if UNITY_EDITOR
    
            private void OnValidate()
            {
    
                if (_field == null)
                    _field = GetComponent<Text>();
    
            }
    
    #endif
    
            #endregion
    
        }
    
    }