CodeStyles

Code Styles

This document is created to guide your style of code.

First rule is:

You MUST follow .editorconfig file!

You can get .editorconfig file from here

Other rules is listed below:

this Preferences

Fields

Do not prefer this

// Prefer:
capacity = 0;

// Over:
this.capacity = 0;

Property

Prefer this

// Prefer:
this.Id = 0;

// Over:
Id = 0;

Method

Do not prefer this

// Prefer:
Display();

// Over:
this.Display();

Event Access

Prefer this.

// Prefer:
this.Elapsed += Handler;

// Over:
Elapsed += Handler;

Predefined type preferences

For locals, parameters and members

⚠ Prefer predefined type instead of framework type.

For example use int instead of Int32

private int _member;
static void M(int argument)
{
	int local;
}

For member access expressions

static void M(int argument)
{
	int local = int.MaxValue;
}

'var' preferences

For built-in types

Prefer explicit type

// Prefer:
int x = 5; // built-in types

// Over:
var x = 5; // built-in types

When variable type is apparent

Prefer var

var cojb = new C(); //type is apparent from assignment expression

Elsewhere

Prefer var

var f = this.Init(); //everywhere else

Code block preferences

Prefer braces

When on multiple lines

// Allow:
if (test) Console.WriteLine("Text");

// Allow:
if (test)
    Console.WriteLine("Text");

// Prefer:
if (test)
{
    Console.WriteLine("Text");
}

// Over:
if (test)
    Console.WriteLine(
		"Text");

Prefer Auto Properties

⚠ Yes

// Prefer:
public int Age { get; }

// Over:
private int age;
public int Age
{
  get
  {
     return age;
  }
}

Prefer Simple using Statement

Yes

// Prefer:
void Method()
{
  using var resource = GetResource();
  ProcessResource(resource);
}

// Prefer:
void Method()
{
	using (var resource = GetResource())
		ProcessResource(resource);
}

// Over:
void Method()
{
  using (var resource = GetResource())
  {
     ProcessResource(resource);
  }
}

Parantheses preferences

In aritmethic operators

* / % + - << >> & ^ |

Never if unnecessary

// Prefer:
var v = a + b * c;

// Over:
var v = a + (b * c);

In other binary operators

&& || ??

Always for clarity

// Prefer:
var v = a || (b && c);

// Over:
var v = a || b && c;

In relational operators

< > <= >= is as !=

Always for clarity

// Prefer:
var v = (a < b) == (c > b);

// Over:
var v = a < b == c > b;

In other operators

Never if unnecessary

// Prefer:
var v = a.b.Length;

// Over:
var v = (a.b).Length;

Expression preferences

Prefer object initializer

⚠ Yes

// Prefer:
var c = new Customer 
{
    Age = 21
};

// Over:
var c = new Customer();
c.Age = 21;

Prefer collection initializer

⚠ Yes

// Prefer:
var list = new List<int>
{
    1,
    2,
    3,
};

// Over:
var list = new List<int>();
list.Add(1);
list.Add(2);
list.Add(3);

Prefer pattern matching over is with cast check

⚠ Yes

// Prefer:
if (o is int i)
{
}

// Over:
if (o is int)
{
    var i = (int)o;
}

Prefer pattern matching over as with null check

⚠ Yes

// Prefer:
if (o is string s)
{
}

// Over:
var s = o as string;
if(s != null)
{
}

Prefer conditional expression over if with assignments

ℹ Prefer Yes up to one single condition!

// Prefer:
string s = expr ? "hello" : "world";

// Over:
string s;
if(expr)
{
    s = "hello";
}
else 
{
    s = "world";
}

Prefer conditional expression over if with returns

ℹ Prefer Yes

// Prefer:
return expr ? "hello" : "world";

// Over:
if(expr)
{
    return "hello";
}
else 
{
    return "world";
}

Prefer explicit tuple name

ℹ Prefer Yes, because it's new feature since C# 7

// Prefer:
public (string name, int age) GetCustomer()
{

}

// Over:
public Tuple<string,int> GetCustomer()
{

}

// Prefer:
(string name, int age) customer = GetCustomer();
var name = customer.name;
var age = customer.age;

// Over:
(string name, int age) customer = GetCustomer();
var name = customer.Item1;
var age = customer.Item2;

Prefer simple default expression

ℹ Prefer Yes

// Prefer:
void DoWork(CancellationToken cancellationToken = default) { }

// Over:
void DoWork(CancellationToken cancellationToken = default(CancellationToken)) { }

Prefer inferred tuple element names

ℹ Prefer Yes

// Prefer:
var tuple = (age, name);

// Over:
var tuple = (age: age, name: name);

Prefer inferred anonymous type member names

ℹ Prefer Yes

// Prefer:
var anon = new { age, name };

// Over:
var anon = new { age = age, name = name };

Prefer local function over anonymous function

⚠ Yes

// Prefer:
int fibonacci(int n)
{
    return n <= 1 ? n : fibonacci(n - 1) + fibonacci(n - 2);
}

// Over:
Func<int, int> fibonacci = null;
fibonacci = (int n) =>
{
    return n <= 1 ? n : fibonacci(n - 1) + fibonacci(n - 2);
}

Prefer compound assignments

ℹ Prefer Yes

// Prefer:
value += 10;

// Over:
value = value + 10;

Prefer index operator

⚠ Yes

// Prefer:
var ch = value[^1];

// Over:
var ch = value[value.Length - 1];

Prefer range operator

⚠ Yes

// Prefer:
var sub = value[1..^1];

// Over:
var sub = value.Substring(1, value.Length - 2);

Use expression body for methods

ℹ Prefer when on single line

class Customer
{
    private int age;
    public int GetAge() => age;
}

Use expression body for constructors

❌ Never

class Customer
{
    private int age;
    public Customer(int age)
    {
        this.age = age;
    }
}

Use expression body for operators

ℹ When on single line

public static ComlexNumber operator +(ComlexNumber c1, ComlexNumber c2)
    => new ComlexNumber(c1.Real + c2.Real, c1.Imaginary + c2.Imaginary);

Use expression body for properties

ℹ When possible

class Customer
{
    private int _age;
    public int Age => _age;
}

Use expression body for indexers

ℹ When possible

class List<T>
{
    private T[] _values;
    public T this[int i] => _values[i];
}

Use expression body for accessors

⚠ When possible

class Customer
{
    private int _age;
    public int Age 
    {
        get => _age;
        set => _age = value;
    }
}

Use expression body for lambdas

When possible

Func<int, string> f = a => a.ToString();

Expression body for local functions

ℹ When possible

class Customer
{
    private int age;
    public int GetAge()
    {
        return GetAgeLocal();

        int GetAgeLocal() => age;
    }
}

Avoid unused value assignments

ℹ Discard

// Prefer:
_ = Computation(); // Unused value is explicitly assigned to discard
int x = 1;

// Over:
var unused = Computation(); // Unused value is explicitly assigned to an unused local
int x = 1;

// Over:
var x = Computation(); // Value assigned here is never used
int x = 1;

Avoid expression statements that implicitly ignore value

Discard

// Prefer:
_ = Computation();

// Over:
var unused = Computation();

// Over:
Computation();

Variable preferences

Prefer inlined variable declaration

ℹ Yes

// Prefer:
if (int.TryParse(value, out int i))
{
}

// Over:
int i;
if (int.TryParse(value, out i))
{
}

Prefer deconstructed variable declaration

ℹ Yes

// Prefer:
var (name, age) = GetPersonTuple();
Console.WriteLine($"{name} {age}");

(int x, int y) = GetPointTuple();
Console.WriteLine($"{x} {y}");

// Over:
var person = GetPersonTuple();
Console.WriteLine($"{person.name} {person.age}");

var point = GetPointTuple();
Console.WriteLine($"{point.x} {point.y}");

'null' checking

Prefer throw-expression

⚠ Yes

// Prefer:
this.s = s ?? throw new ArgumentNullException(nameof(s));

// Over:
if (s == null)
    throw new ArgumentNullException(nameof(s));

this.s = s;

Prefer conditional delegate call

⚠ Yes

// Prefer:
func?.Invoke(args);

// Over:
if (func != null)
{
    func(args);
}

Prefer coalesce expression

❌ YES!

// Prefer:
var v = x ?? y;

// Over:
var v = x != null ? x : y; // or
var v = x == null ? y : x;

Prefer null propagition

❌ YES!

// Prefer:
var v = o?.ToString();

// Over:
var v = o == null ? null : o.ToString(); // or
var v = o != null ? o.ToString() : null;

Prefer is null for reference equality checks

⚠ Yes

// Prefer:
if (value1 is null)
    return;

if (value2 is null)
    return;

// Over:
if (object.ReferenceEquals(value1, null))
    return;

if ((object)value2 == null)
    return;

'using' preferences

Prefered using directive placement

Outside namespace

// Prefer:
using System;
using System.Linq;

namespace Namespace
{
    class Customer
    {
    }
}

// Over:
namespace Namespace
{
    using System;
    using System.Linq;

    class Customer
    {
    }
}

Modifier preferences

Prefer readonly fields

⚠ Yes

// Prefer:
// '_value' can only be assigned in constructor
private readonly int _value = 0;

// Over:
// '_value' can be assigned anywhere
private int _value = 0;

Prefer static local functions

❌ YES!

If a local function doesn't use any member from method body, just declare it as static!

void Method()
{
    // Prefer:
    static int fibonacci(int n)
    {
        return n <= 1 ? n : fibonacci(n - 1) : fibonacci(n - 2);
    }
}

void Method()
{
    // Over:
    int fibonacci(int n)
    {
        return n <= 1 ? n : fibonacci(n - 1) : fibonacci(n - 2);
    }
}

Parameter preferences

Avoid unused parameters

ℹ All methods

// Prefer:
public void M()
{
}

// Over:
public void M(int param)
{
}