Introduction: The Legend of "Dead" C#
You've probably heard that C# is a language for "corporate" environments, where everything is boring, slow, and covered in a layer of enterprise bureaucracy. But the truth is that a C# developer today is a universal IT soldier. They write fast microservices on ASP.NET Core, optimize database queries via Entity Framework, and sometimes even integrate machine learning with ML.NET.
In this article, I won't be discussing abstract theories. We'll go through a typical workday of a C# programmer in a real company: from morning coffee to pushing code to production. You'll see code examples, tools, and life hacks that will save you hours of work.
08:30 — Morning: Coffee, Email, and Task Board
The day doesn't start with code, but with context. First, I open Slack and Jira. In a typical team, there's a morning stand-up (daily stand-up). During it, we answer three questions:
- What was done yesterday?
- What will I do today?
- Are there any blockers?
After the stand-up, a quick review of colleagues' pull requests. Code review in C# isn't just a "checkbox." It's important to check for memory leaks (especially with IDisposable) and whether async/await is used correctly.
Real-life example: code review of an async method
// Bad: blocking call inside an async methodpublic async Task<User> GetUserAsync(int id){ var user = _context.Users.Find(id); // .Find — synchronous! return await Task.FromResult(user); // Useless wrapper}
// Good: fully asynchronouspublic async Task<User> GetUserAsync(int id){ return await _context.Users.FindAsync(id); // Real asynchrony}Such a small thing can kill performance under load. Therefore, a C# programmer must monitor asynchrony at every step.
10:00 — Working on a Task: Writing a New API Endpoint
Today in the backlog, there's a task: "Add product filtering by price." This is a typical story for a .NET developer. I work in Visual Studio 2022 with ReSharper (yes, it's slow, but I can't live without it).
Step 1: Model and DTO
First, we define the data model. Let's say we have Entity Framework Core and a PostgreSQL database.
public class Product{ public int Id { get; set; } public string Name { get; set; } public decimal Price { get; set; } public string Category { get; set; }}
public class ProductFilterDto{ public decimal? MinPrice { get; set; } public decimal? MaxPrice { get; set; } public string? Category { get; set; }}Step 2: Repository with IQueryable
The main trick is not to pull all data into memory, but to use IQueryable. This allows forming the SQL query on the database side.
public async Task<List<Product>> GetFilteredProductsAsync(ProductFilterDto filter){ var query = _context.Products.AsQueryable();
if (filter.MinPrice.HasValue) query = query.Where(p => p.Price >= filter.MinPrice.Value);
if (filter.MaxPrice.HasValue) query = query.Where(p => p.Price <= filter.MaxPrice.Value);
if (!string.IsNullOrEmpty(filter.Category)) query = query.Where(p => p.Category == filter.Category);
return await query.ToListAsync();}Note: we don't call .ToList() until the very end. This is a basic but critically important pattern for any C# developer.
Step 3: ASP.NET Core Controller
[ApiController][Route("api/[controller]")]public class ProductsController : ControllerBase{ private readonly IProductRepository _repo;
public ProductsController(IProductRepository repo) =&g