За основу Style Guide был взят кодстайл Microsoft
// ПЛОХО
var a = new List<Student>();
var stds = new List<Student>();
var list = new List<Student>();
// ХОРОШО
var students = new List<Student>();
bool isRed = color == Colors.Red; // Good
bool isNotBlue = color != Colors.Blue; // Bad
if (!isRed // Ok
&& !isNotBlue) // It is not ok
return ...
Имя состоит из prefix? + action (A) + high context (HC) + low context? (LC).
- Action - это действие, которое выполняется (get, set, remove, etc.)
- HC и LC - это выделение более значимых элементов. Название метода GetUserAssignments подразумевает, что есть основная сущность (User) и ассоциированные зависимые (Assignments).
// ХОРОШО
public Student? FindStudent(int id)
{
/* ищем студента */
// возвращаем студента вне зависимости от того, null это или нет
return student;
}
null).Правильно:
public Person? FindEldestChild()
{
// If _children in empty - returns null
return _children
.OrderByDescending(p => p.BirthDate)
.SingleOrDefault();
}
Неправильно:
public Person? FindEldestChild()
{
// If _children in empty - throws exception
return _children
.OrderByDescending(p => p.BirthDate)
.Single();
}
bool флаг на выходе из метода)Правильно:
public bool TryWithdrawMoney(CreditCard creditCard, int password, double moneyToWithdraw)
{
// если пароль не верный, возвращаем false
if (!creditCard.IsPasswordCorrect(password))
return false;
// если пароль верный, то снимаем деньги
creditCard.Withdraw(moneyToWithdraw);
return true;
}
Неправильно:
public void TryWithdrawMoney(CreditCard creditCard, int password, double moneyToWithdraw)
{
// если пароль совпадает, снимаем деньги
if (creditCard.IsPasswordCorrect(password))
creditCard.Withdraw(moneyToWithdraw);
}
Правильно:
var location = "Yerevan";
var age = 69;
var relevantStudents = _students
.Where(x => x.Location.Equals(location))
.Where(x => x.Age.Equals(age));
foreach (var student in relevantStudents)
{
Console.WriteLine($"Найден дед - {student.Name}");
}
Неправильно:
var location = "Yerevan";
var age = 69;
var relevantStudents = _students
.Where(x => x.Location.Equals(location))
.Where(x => x.Age.Equals(age));
foreach (var student in relevantStudents)
{
Console.WriteLine($"Найден дед - {student.Name}");
}
Правильно:
public class Student
{
public int Id { get; }
public string FirstName { get; }
public string LastName { get; }
public string FullName => $"{FirstName} {LastName}";
public override string ToString()
=> $"[{Id}] {FullName}";
}
Неправильно:
public class Student
{
public int Id { get; }
public string FirstName { get; }
public string LastName { get; }
public string FullName => $"{FirstName} {LastName}";
public override string ToString()
=> $"[{Id}] {FullName}";
}
public class Student
{
public int Id { get; }
public string FirstName { get; }
public string LastName { get; }
public string FullName => $"{FirstName} {LastName}";
public override string ToString()
=> $"[{Id}] {FullName}";
}
return.Правильно:
public int Calculate()
{
var x = 420 * 228;
var y = x / 1337d;
return x + y;
}
Неправильно:
public class Student
public int Calculate()
{
var x = 420 * 228;
var y = x / 1337d;
return x + y;
}
Правильно:
public Student AddStudent(string name, string surname)
{
var student = new Student(name, surname);
// сравниваем с читаемой константов
if (_students.Count >= MaxStudentsAmount)
throw new Exception("Students limit exceeded");
_students.Add(stident);
return student;
}
Неправильно:
public Student AddStudent(string name, string surname)
{
var student = new Student(name, surname);
// сравниваем с магическим числом
if (_students.Count >= 20)
throw new Exception("Students limit exceeded");
_students.Add(stident);
return student;
}
Правильно:
double percents = bankAccount.CalculatePercents();
decimal percents = bankAccount.CalculatePercents();
Money percents = bankAccount.CalculatePercents();
var studentInfo = new UserInfo(); // тип переменной понятен, тк это инициализация
Неправильно:
var percents = bankAccount.CalculatePercents();
Правильно:
switch (deposit)
{
case < LowerThreshold:
Console.WriteLine("Your percent is 3");
break;
case < MiddleThreshold:
Console.WriteLine("Your percent is 5");
break;
default:
throw new Exception("Unexpected case");
}
Неправильно:
switch (deposit)
{
case < LowerThreshold:
Console.WriteLine("Your percent is 3");
break;
case < MiddleThreshold:
Console.WriteLine("Your percent is 5");
break;
}
// ПЛОХО
if (MaxStudentsAmount <= _students.Count)
throw new Exception("Students limit exceeded");
// ХОРОШО
if (_students.Count >= MaxStudentsAmount)
throw new Exception("Students limit exceeded");
// ПЛОХО
public void SomeCalculations(List<int> nubmers)
{
var oddOnly = new List<int>();
var oddOnlyUnique = new List<int>();
var oddOnlyUniqueLimited = new List<int>();
int numbersCount;
oddOnly.AddRange(numbers.Where(...));
// какие-то вычисления
oddOnlyUnique.AddRange(oddOnly.Where(...));
// какие-то вычисления
oddOnlyUniqueLimited.AddRange(oddOnlyUnique.Take(...));
}
// УЖЕ ЛУЧШЕ
public void SomeCalculations(List<int> nubmers)
{
var oddOnly = numbers.Where(...);
// какие-то вычисления
var oddOnlyUnique = oddOnly.Where(...));
// какие-то вычисления
var oddOnlyUniqueLimited = oddOnlyUnique.Take(...);
var numbersCount = oddOnlyUniqueLimited.Count();
}
// не очень ХОРОШО
if (_students.Count >= MaxStudentsAmount)
{
throw new Exception("Students limit exceeded");
}
else
{
_students.Add(stident);
return student;
}
// ХОРОШО
if (_students.Count >= MaxStudentsAmount)
throw new Exception("Students limit exceeded");
_students.Add(stident);
return student;
// ПЛОХО (не нада так пажалуста)
while (true)
{
// что угодно тут будет плохо :)
// особенно, если не будет break;
}
// ЛУЧШЕ
for (int i = 0; i < studentsConut; ++i)
{
// почти всё что угодно тут будет лучше чем предыдущий вариант
// особенно, если тут не будет while (true)
}
// ПЛОХО
public List<Student> FindStudents(int course)
{
// объявляем лист (но не инициализируем)
List<Student> students;
/* ищем студентов любым возможным методом */
// если студенты не нашлись, возвращаем null
if (students.Count is null)
return null;
// возвращаем студентов, если хоть кто-то нашёлся
return students;
}
// ХОРОШО
public List<Student> FindStudents(int course)
{
// создаём пустой лист
var students = new List<Student>();
/* ищем студентов любым возможным методом */
// возвращаем студентов даже, если это пустой лист (не null)
return students;
}
// ПЛОХО
public void FindStudentByFullName(string name, string surname)
{
/* поиск студента без проверки входных данных */
}
// ХОРОШО
public void FindStudentByFullName(string name, string surname)
{
if (string.IsNullOrWhiteSpace(name))
throw new ArgumentException("Name to find student is empty");
if (string.IsNullOrWhiteSpace(name))
throw new ArgumentException("Surname to find student is empty");
/* поиск студента после проверки входных данных */
}
// ХОРОШО
public MegaFaculty(string facultyName)
{
// валидация
if (string.IsNullOrWhiteSpace(facultyName))
throw new ArgumentException("Mega faculty name is empty");
// инициализация, не зависящая от аргументов
_courses = new List<OgnpCourse>();
// инициализация полей аргументами
Name = facultyName;
/* сложная инициализация с вызовом различных методов */
NotifyISU(this);
}
// ХОРОШО
public int Value { get; set; }
// ПЛОХО
public int Value
{ get; set; }
get аксессора// ХОРОШО
public IReadOnlyCollection<string> Values => _values;
// ПЛОХО
public IReadOnlyCollection<string> Values
{
get
{
return _values;
}
}
public IReadOnlyCollection<string> Values
{
get => _values;
}
== для сравнения не числовых типов. Не переопределяйте оператор == для не числовых типов.Методы расширения должны выделяться в специальные классы. Они должны иметь соответствующий постфикс Extensions.
Весь исходный код должен быть написан на английском. Это касается нейминга, комментариев и ошибок. Если есть необходимость использовать другой язык, то нужно применить инструменты локализации.
Для обозначения отсутствия значения стоит использовать null, а не default. Для значимых типов стоит возвращать Nullable.
Избегайте кастов там, где можно их не использовать. Программа должна стремиться к повышению типизации и увеличению количества мест, где происходят проверки во время компиляции.
Минимизируйте количество ап кастов. Старайтесь не использовать более общие типы в сигнатурах, если они не поддерживаются.
При написании цепочки вызовов методов, переносите каждый вызов на отдельную строку.
Для проверки на null использовать конструкции is null и is not null.
Используйте Type.Parse вместо Convert.ToType (например, int.Parse вместо Convert.ToInt32).
Название namespace должно содержать название проекта и все папки через точку, ведущие от корня проекта к текущему файлу.
Пример структуры проекта:
Project
Users
Models
Entities
Student.cs
Services
Orders
Models
Entities
Services
При такой структуре проекта название namespace в файле Student.cs будет Project.Users.Entities
record.Expression<Func<TEntity, TDto>>. Они должны напрямую сетить все нужные поля и не использовать конструкторы или статические методы.