--- tags: guides --- # C# Coding guidelines authors: **Nazarii Taran**, **Roman Makhnyk** ## Naming * General rule for naming entities - **PascalCase**. * Start with a small letter (**camelCase**): 1. Local varaibles; 2. Formal parameters of the method. * The names of solutions, projects, folders - **PascalCase**. * The names of classes, structutres, constants, properties, methods - **PascalCase**. * Use the underscore character (```_```) only in field names (except for static readonly - the rule for them is the same as for constants). * Interface names begin with the prefix ```I```. * Names of generic parameters begin with the prefix ```T```. * Do not use redundant ```this```. * Never specify access modifiers on members of interfaces. * Always specify access modifiers to other code members. ### Examples :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 * The members of the class must be sorted in the following order: 1. Fields; 2. Constructors; 3. Properties; 4. Indexers; 5. Events; 6. Methods. * Within each group, sort by static\instance: 1. Constants; 2. Static members; 3. None-static. * Within each group is sorting by visibility: 1. public; 2. protected; 3. private. ### Examples :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 * All enum members must be numbered * Each member must be on its own line * Each member is named with a capital letter ### Examples :broken_heart: ```csharp= public enum UserStatus { active, inactive } ``` :green_heart: ```csharp= public enum UserStatus { Active = 0, Inactive = 1 } ``` ## Formatting * Tabulation - *4 spaces*. Use a space character, not a tab; * Constructs **if-else**, **switch**, **for**, **foreach**, **do**, **do-while**, **using** must be framed in brackets ```{ }``` even if there is one line; * Brackets must be placed one under the other; * There must be an empty line after the structures listed above; * There must be an empty line between class members; * There must be a space on the sides of the binary operator (+, -, *, \, etc.); ### Examples :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 * Each program entity (class, interface, enam, delegate) must be in its own file; * The maximum number of method parameters is 5; * The maximum line length is 200 characters; * The maximum length of the method is 50 lines; * The maximum level of nesting for constructions ```if'', ``foreach'', etc. - 2. ## Other suggestions * Avoid dead conditional code (https://docs.microsoft.com/en-us/dotnet/fundamentals/code-analysis/quality-rules/ca1508). * Validate public method arguments (https://docs.microsoft.com/en-us/dotnet/fundamentals/code-analysis/quality-rules/CA1062). * Use reserved type names (https://docs.microsoft.com/en-us/dotnet/fundamentals/code-analysis/style-rules/ide0049). * Order of access modifiers: public, private, protected, internal, static, extern, new, virtual, abstract, sealed, override, readonly, unsafe, volatile, async. * For simple value assignments or returns, use conditional expressions with the ternary operator (https://docs.microsoft.com/en-us/dotnet/fundamentals/code-analysis/style-rules/ide0046). * If possible, use auto-properties (https://docs.microsoft.com/en-us/dotnet/fundamentals/code-analysis/style-rules/ide0032). * Use collection initializers if necessary (https://docs.microsoft.com/en-us/dotnet/fundamentals/code-analysis/style-rules/ide0028). * Use object initializers when needed (https://docs.microsoft.com/en-us/dotnet/fundamentals/code-analysis/style-rules/ide0017). * Use **Coalesce** expressions to single-line check for ```null``` and replace with a suitable default value (https://docs.microsoft.com/en-us/dotnet/fundamentals/code-analysis/style-rules/ide0029-ide0030). * Use the **null-conditional** operator to one-line test for ```null``` if you must use object members (https://docs.microsoft.com/en-us/dotnet/fundamentals/code- analysis/style-rules/ide0031). * Use **pattern matching** to convert types (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). * Use the **index-from-end** operator instead of ```.Length - 1''` (https://docs.microsoft.com/en-us/dotnet/fundamentals/code-analysis/style-rules/ ide0056). * Use the **range operator** (https://docs.microsoft.com/en-us/dotnet/fundamentals/code-analysis/style-rules/ide0057). * Sort the usings block alphabetically (standard sorting in VS 2019).