--- tags: guides --- # C# Coding guidelines authors: **Nazarii Taran**, **Roman Makhnyk** old page: https://hackmd.io/@kRVOe6MkQdSn1HsuDXuQAw/By9TzQeIN ## Naming * Загальне правило для іменування сутностей - **PascalCase**. * З маленької літери починаються (**camelCase**): 1. Локальні змінні; 2. Формальні параметри методу. * Імена солюшенів, проектів, папок - **PascalCase**. * Імена класів, структур, констант, властивостей, методів - **PascalCase**. * Використовувати символ нижнього підкреслення (```_```) тільки в іменах полів (крім static readonly - до них правило таке ж як до констант). * Імена інтерфейсів починаються з префіксу ```I```. * Імена generic-параметрів починаються з префіксу ```T```. * Не використовуйте надлишковий ```this```. * Ніколи не вказуйте модифікатори доступу до членів інтерфейсів. * Завжди вказуйте модифікатори доступу до інших членів коду. ### Приклади :broken_heart: ```csharp= namespace Project_Name { } namespace projectName { } public class userService { } public class User_Service { } public interface Editable { } public interface editable { } public class BadClassMemberNamingDemo { public const string DEFAULT_NAME = "No Name"; private int FieldName; private int fieldName; public void method() { } public void method_name() { } public void BadArgumentsNamingDemo(int FirstArgument, int Second_Argument) { } public void BadGenericNamingDemo<Entity, otherEntity>() { } public void BadLocalVariableNamingDemo() { int local_variable = 0; } } ``` :green_heart: ```csharp= namespace ProjectName { } namespace Extensions { } public class UserService { } public interface IEditable { } public interface IUserService { } public class GoodMemberNamingDemo { public const string DefaultName = "No Name"; private int _fieldName; public int PropertyName { get; set; } public void MethodName() { } public void GoodArgumentsNamingDemo(int firstArgument, int secondArgument) { } public void GoodGenericNamingDemo<TEntity>() { } public void GoodLocalVariableNamingDemo() { int localVariable = 0; } } ``` ## Class layout * Члени класу мають бути відсортовані у такому порядку: 1. Поля; 2. Конструктори; 3. Властивості; 4. Індексатори; 5. Події; 6. Методи. * Усередині кожної групи сортування по static\instance: 1. Константи; 2. Static члени; 3. None-static. * Усередині кожної групи сортування по області видимості: 1. public; 2. protected; 3. private. ### Приклади :broken_heart: ```csharp= public class MyClass { public void Method1() { } public int Property1 { get; set; } private static int staticField = 0; public MyClass() { } private int field1; public const string Const = "const"; protected Property2 { get; set; } public static void Static1() { } private void Method3() { } private static void Static2() { } public void Method2() { } } ``` :green_heart: ```csharp= public class MyClass { public const string Const = "const"; private static int staticField = 0; private int field1; public MyClass() { } public string Property2 { get; set; } protected int Property1 { get; set; } public static void Static1() { } private static void Static2() { } public void Method1() { } protected void Method2() { } private void Method3() { } } ``` ## Enum * Усі члени enum мають бути пронумеровані * Кожен член повинен бути на своєму рядку * Кожен член називається з великої літери ### Приклади :broken_heart: ```csharp= public enum UserStatus { active, inactive } ``` :green_heart: ```csharp= public enum UserStatus { Active = 0, Inactive = 1 } ``` ## Formatting * Табуляція - *4 пробіли*. Використовувати символ пробілу, а не таб; * Конструкції **if-else**, **switch**, **for**, **foreach**, **do**, **do-while**, **using** повинні бути обрамлені в дужки ```{ } ``` навіть якщо там один рядок; * Скобочки повинні бути розташовані одна під одною; * Після перерахованих вище конструкцій повинен бути порожній рядок; * Між членами класу має бути порожній рядок; * З боків бінарного оператора (+, -, *, \ и т.д.) має бути пробіл; ### Приклади :broken_heart: ```csharp= public UserModel GetUserById(long id) { var user = this.repository.GetById<User>(id); if (user == null) { return UserModel.NullObject; } foreach (UserSkills skill in user.Skills) { // logic } return user.ToUserModel(); } ``` :green_heart: ```csharp= public UserModel GetUserById(long id) { var user = this.repository.GetById<User>(id); if (user == null) { return UserModel.NullObject; } foreach (UserSkills skill in user.Skills) { // logic } return user.ToUserModel(); } ``` :broken_heart: ```csharp= public class User { public User() : this(-1, "No Name", -1) { } public User(long id, string name, int age) { this.Id = id; this.Name = name; this.Age = age; } public long Id { get; set; } public string Name { get; set; } public int Age { get; set; } } ``` :green_heart: ```csharp= public class User { public User() : this(-1, "No Name", -1) { } public User(long id, string name, int age) { Id = id; Name = name; Age = age; } public long Id { get; set; } public string Name { get; set; } public int Age { get; set; } } ``` :broken_heart: ```csharp= int devision=5/3; string result = "sdf"+"sdf"; for (int i=0;i<itemCount;i++) { } ``` :green_heart: ```csharp= int devision = 5 / 3; string result = "sdf" + "sdf"; for (int i = 0; i < itemCount; i++) { } ``` :broken_heart: ```csharp= public void Method() { if (condition) { } } ``` :green_heart: ```csharp= public void Method() { if (condition) { } } ``` :broken_heart: ```csharp= public void Method() { if (condition) // one line of logic foreach (var item in collection) // one line of logic } ``` :green_heart: ```csharp= public void Method() { if (condition) { // one line of logic } foreach (var item in collection) { // one line of logic } } ``` ## Clean code * Кожна програмна сутність (клас, інтерфейс, енам, делегат) має бути у своєму файлі; * Максимальна кількість параметрів методу - 5; * Максимальна довжина рядка – 200 символів; * Максимальна довжина методу – 50 рядків; * Максимальний рівень вкладеності для конструкцій ```if```, ```foreach``` і т.д. - 2. ## Other suggestions * Уникайте мертвого умовного коду (https://docs.microsoft.com/en-us/dotnet/fundamentals/code-analysis/quality-rules/ca1508). * Валідуйте аргументи публічних методів (https://docs.microsoft.com/en-us/dotnet/fundamentals/code-analysis/quality-rules/CA1062). * Використовуйте зарезервовані назви типів (https://docs.microsoft.com/en-us/dotnet/fundamentals/code-analysis/style-rules/ide0049). * Порядок модифікаторів доступу: public, private, protected, internal, static, extern, new, virtual, abstract, sealed, override, readonly, unsafe, volatile, async. * Для простих присвоювань значень або їх повернення використовуйте умовні вирази з тернарним оператором (https://docs.microsoft.com/en-us/dotnet/fundamentals/code-analysis/style-rules/ide0046). * Якщо можливо – використовуйте автовластивості (https://docs.microsoft.com/en-us/dotnet/fundamentals/code-analysis/style-rules/ide0032). * За потреби використовуйте ініціалізатори колекцій (https://docs.microsoft.com/en-us/dotnet/fundamentals/code-analysis/style-rules/ide0028). * За потреби використовуйте ініціалізатори об'єктів (https://docs.microsoft.com/en-us/dotnet/fundamentals/code-analysis/style-rules/ide0017). * Використовуйте **Coalesce** вирази для однорядкової перевірки на ```null``` і заміни на підходяще стандартне значення (https://docs.microsoft.com/en-us/dotnet/fundamentals/code-analysis/style-rules/ide0029-ide0030). * Використовуйте **null-conditional** оператор для однорядкової перевірки на ```null```, якщо необхідно використовувати члени об'єкта (https://docs.microsoft.com/en-us/dotnet/fundamentals/code-analysis/style-rules/ide0031). * Використовуйте **pattern matching** для перетворення типів (https://docs.microsoft.com/en-us/dotnet/fundamentals/code-analysis/style-rules/ide0020-ide0038 , https://docs.microsoft.com/en-us/dotnet/fundamentals/code-analysis/style-rules/ide0019). * Використовуйте **index-from-end** оператор замість ```.Length - 1``` (https://docs.microsoft.com/en-us/dotnet/fundamentals/code-analysis/style-rules/ide0056). * Використовуйте **range operator** (https://docs.microsoft.com/en-us/dotnet/fundamentals/code-analysis/style-rules/ide0057). * Сортуйте блок usings за абеткою (стандартне сортування в VS 2019).