Почему C# — это не про «корпораты» и скуку?
В мире IT сложился стереотип: C# — это язык для скучных enterprise-проектов, банковских систем и порталов госуслуг. Но если отбросить предрассудки, то выяснится, что на C# написаны Stack Overflow, Unity, часть Visual Studio и даже JetBrains Rider. Давайте разберём реальные кейсы компаний, которые используют C# в production, и посмотрим на код, который за этим стоит.
Эта статья — не сухая теория, а разбор живых проектов с примерами, которые вы сможете адаптировать под свои задачи. Поехали.
Кейс 1: Stack Overflow — как C# держит 1 миллиард запросов в месяц
Stack Overflow — это, пожалуй, самый известный пример использования C# в высоконагруженном проекте. Сайт обрабатывает более 1 миллиарда просмотров страниц в месяц, и при этом работает на ASP.NET MVC (сейчас .NET Core) с использованием Redis и Elasticsearch.
Архитектура и почему C#?
Команда Stack Overflow выбрала C# из-за производительности, строгой типизации и отличной поддержки многопоточности. Ключевая фишка — минимальное использование сторонних библиотек. Они сами написали свой ORM (Dapper) и свой кэширующий слой.
Пример кода: высокопроизводительный кэш с Redis
Один из секретов скорости Stack Overflow — агрессивное кэширование. Вот как примерно выглядит их подход к работе с Redis через StackExchange.Redis:
public class CacheService
{
private readonly IDatabase _cache;
private readonly TimeSpan _defaultExpiry = TimeSpan.FromMinutes(10);
public CacheService(IConnectionMultiplexer redis)
{
_cache = redis.GetDatabase();
}
public async Task<T> GetOrSetAsync<T>(string key, Func<Task<T>> factory)
{
// Попытка получить из кэша
var cached = await _cache.StringGetAsync(key);
if (cached.HasValue)
{
return JsonSerializer.Deserialize<T>(cached);
}
// Если нет — вызываем фабрику и сохраняем
var value = await factory();
var serialized = JsonSerializer.Serialize(value);
await _cache.StringSetAsync(key, serialized, _defaultExpiry);
return value;
}
}
Почему это круто? Они не просто кэшируют всё подряд — они используют cache-aside pattern и ставят TTL (время жизни) в зависимости от типа данных. Например, для списка вопросов — 30 секунд, для профиля пользователя — 5 минут.
Кейс 2: Unity — C# как язык для игр и 3D
Unity — главный игровой движок для инди-разработчиков и крупных студий. Внутри он написан на C++ (ядро), но весь скриптинг для игр — на C#. Более 50% мобильных игр в мире сделаны на Unity, и это не только «Angry Birds», но и Hearthstone или Pokémon GO.
Почему C#, а не C++?
Unity выбрал C# из-за баланса: он быстрее, чем Python или JavaScript, но при этом безопаснее и проще, чем C++. Сборщик мусора (GC) может быть проблемой, но в Unity его научились контролировать.
Пример кода: оптимизация через пул объектов
В играх часто создаются и уничтожаются объекты (пули, враги, частицы). Чтобы избежать фризов из-за GC, используют Object Pool. Вот как это выглядит в C#:
public class BulletPool : MonoBehaviour
{
private Queue<Bullet> _pool = new Queue<Bullet>();
[SerializeField] private Bullet _bulletPrefab;
public Bullet Get()
{
if (_pool.Count > 0)
{
var bullet = _pool.Dequeue();
bullet.gameObject.SetActive(true);
return bullet;
}
return Instantiate(_bulletPrefab);
}
public void Return(Bullet bullet)
{
bullet.gameObject.SetActive(false);
_pool.Enqueue(bullet);
}
}
Вместо Destroy() (который вызывает GC) — просто деактивируем объект и кладём обратно в очередь. Это даёт прирост FPS до 20-30% на мобильных устройствах.
Кейс 3: JetBrains Rider — когда C# пишут на C#
JetBrains Rider — это IDE для .NET разработчиков, написанная на Java (IntelliJ Platform), но вся логика анализа кода, рефакторинга и подсветки синтаксиса — на C#. Да, они используют ReSharper как движок, который написан полностью на C#.
Как они используют C# для анализа C#?
В Rider есть Roslyn — компиляторная платформа от Microsoft. Они надстраивают поверх неё свои анализаторы. Например, чтобы найти все места, где используется List<T> вместо массива, они пишут свой Roslyn Analyzer.
Пример кода: кастомный анализатор
Представьте, что вы хотите запретить использовать ArrayList (deprecated) в коде проекта. Вот как это сделать с помощью Roslyn:
[DiagnosticAnalyzer(LanguageNames.CSharp)]
public class AvoidArrayListAnalyzer : DiagnosticAnalyzer
{
private const string DiagnosticId = "AVOID_ARRAYLIST";
private static readonly DiagnosticDescriptor Rule = new DiagnosticDescriptor(
DiagnosticId,
"Избегайте использования ArrayList",
"Используйте List<T> вместо ArrayList для типобезопасности",
"Performance",
DiagnosticSeverity.Warning,
isEnabledByDefault: true);
public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics
=> ImmutableArray.Create(Rule);
public override void Initialize(AnalysisContext context)
{
context.RegisterSyntaxNodeAction(AnalyzeObjectCreation,
SyntaxKind.ObjectCreationExpression);
}
private void AnalyzeObjectCreation(SyntaxNodeAnalysisContext context)
{
var creation = (ObjectCreationExpressionSyntax)context.Node;
var type = context.SemanticModel.GetTypeInfo(creation).Type;
if (type?.ToString() == "System.Collections.ArrayList")
{
context.ReportDiagnostic(Diagnostic.Create(Rule, creation.GetLocation()));
}
}
}
Этот код встраивается прямо в IDE и подсвечивает проблемные места в реальном времени. Вот так C# помогает писать лучший C#.
Кейс 4: Telerik (Progress) — UI компоненты для миллионов разработчиков
Компания Progress, создатель Telerik и Kendo UI, использует C# для построения ASP.NET Core UI Controls. Их библиотеки используются в 150 000+ компаний по всему миру. Секрет успеха — не просто «кнопки и таблицы», а мощная серверная логика на C#.
Пример: серверная пагинация с Entity Framework
Когда вы используете Telerik Grid, данные не грузятся все сразу — они запрашиваются с сервера порциями. Вот как это реализовано на C#:
public async Task<GridResponse<Product>> GetProducts(GridRequest request)
{
var query = _context.Products.AsQueryable();
// Фильтрация
if (!string.IsNullOrEmpty(request.Filter))
{
query = query.Where(p =>