---
# System prepended metadata

title: C# Coding guidelines
tags: [guides]

---

---
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).