Современный C#: Основы и передовые практики

Введение
C# — это высокоуровневый, объектно-ориентированный язык программирования, разработанный Microsoft. В 2025 году он остается одним из самых популярных языков благодаря своей универсальности, производительности и постоянному развитию. C# используется в различных областях, включая веб-разработку (ASP.NET Core), создание игр (Unity), мобильные приложения (Xamarin), десктопные приложения (WPF, MAUI) и облачные решения (Azure). В этой статье мы рассмотрим ключевые концепции, новые возможности и лучшие практики современного C#.

1. Современный синтаксис и функциональные возможности

1.1. Типы record и init-only свойства

Типы record появились в C# 9.0 и предназначены для создания неизменяемых (immutable) объектов с автоматической реализацией EqualsGetHashCode и ToString. Они идеально подходят для DTO (Data Transfer Objects) и моделей данных.

public record Person(string FirstName, string LastName, int Age);
var person1 = new Person(«John», «Doe», 30);
var person2 = person1 with { Age = 31 };

Свойства init позволяют устанавливать значения только при инициализации:

public class Product
{
public string Name { get; init; }
public decimal Price { get; init; }
}
var product = new Product { Name = «Laptop», Price = 999.99m };

1.2. Pattern Matching

Pattern matching упрощает проверку типов и структур данных:

object obj = «Hello, world!»;
if (obj is string message)
{
Console.WriteLine($»Длина строки: {message.Length}«);
}
var result = obj switch
{
int i => $»Целое число: {i}«,
string s => $»Строка: {s}«,
_ => «Неизвестный тип»
};

1.3. Лямбда-выражения и локальные функции

Лямбда-выражения делают код более лаконичным:

Func<int, int, int> add = (x, y) => x + y;
Console.WriteLine(add(5, 3));

Локальные функции полезны для инкапсуляции логики внутри методов:

public void ProcessData(List<int> data)
{
int CalculateAverage() => data.Sum() / data.Count;
Console.WriteLine($»Среднее: {CalculateAverage()}«);
}

2. Асинхронное программирование

2.1. async/await

Асинхронное программирование позволяет избегать блокировки потока при выполнении I/O-операций:

public async Task<string> DownloadDataAsync(string url)
{
using var client = new HttpClient();
return await client.GetStringAsync(url);
}

2.2. ValueTask

ValueTask — это оптимизация для случаев, когда результат может быть доступен синхронно:

public ValueTask<int> GetValueAsync(bool fromCache)
{
return fromCache ? new ValueTask<int>(42) : new ValueTask<int>(LoadFromDbAsync());
}
private async Task<int> LoadFromDbAsync() => await Task.FromResult(100);

2.3. Параллельное выполнение задач

Task.WhenAll и Task.WhenAny позволяют эффективно управлять несколькими асинхронными операциями:

var task1 = DownloadDataAsync(«https://api.example.com/data1»);
var task2 = DownloadDataAsync(«https://api.example.com/data2»);
await Task.WhenAll(task1, task2);

3. Работа с данными и LINQ

3.1. LINQ (Language Integrated Query)

LINQ предоставляет мощные инструменты для работы с коллекциями:

var numbers = new List<int> { 1, 2, 3, 4, 5 };
var evenNumbers = numbers.Where(n => n % 2 == 0).ToList();
var squares = numbers.Select(n => n * n);

3.2. Иммутабельные коллекции

Иммутабельные коллекции (ImmutableListImmutableDictionary) полезны для многопоточных приложений:

using System.Collections.Immutable;
var immutableList = ImmutableList.Create(1, 2, 3);
var newList = immutableList.Add(4);

3.3. Span<T> и Memory<T>

Эти типы позволяют работать с памятью более эффективно, избегая лишних аллокаций:

int[] array = { 1, 2, 3, 4, 5 };
Span<int> span = array.AsSpan();
int sum = 0;
foreach (var num in span)
{
sum += num;
}

4. Обработка ошибок и безопасность

4.1. Исключения и фильтры

Фильтры исключений позволяют обрабатывать ошибки более гибко:

try
{
// Код, который может вызвать исключение
}
catch (HttpRequestException ex) when (ex.StatusCode == 404)
{
Console.WriteLine(«Ресурс не найден»);
}

4.2. Nullable Reference Types

Эта функция помогает избежать NullReferenceException:

#nullable enable
string? nullableString = null;
string nonNullableString = «Hello»;

5. Лучшие практики

  • Используйте Dependency Injection для управления зависимостями:

services.AddScoped<IMyService, MyService>();

  • Пишите модульные тесты с помощью xUnit или NUnit:

[Fact]
public void Test_Addition()
{
Assert.Equal(4, 2 + 2);
}

  • Оптимизируйте производительность с помощью Span<T>ArrayPool и MemoryCache.
  • Используйте Source Generators для автоматической генерации кода.

Заключение

Современный C# — это мощный инструмент для разработки высокопроизводительных и надежных приложений. Используя новые возможности языка, такие как record, pattern matching, асинхронное программирование и LINQ, вы сможете писать чистый и эффективный код. Для углубленного изучения рекомендуется ознакомиться с документацией Microsoft, книгами по C# и участием в open-source проектах.Для дальнейшего изучения рекомендуем:

  1. Современные стандарты C# и .NET (C# 12, .NET 8/9)
  2. Принципы Domain-Driven Design (DDD) для сложных бизнес-приложений
  3. Методы профилирования и оптимизации (Benchmark.NET, dotTrace, PerfView)
  4. Работу с распределёнными системами (Microservices, Event Sourcing, CQRS)
  5. Продвинутые техники параллельного программирования (Channels, Actor Model, Dataflow)