C# 10 and 11 introduced several features that reduce everyday boilerplate in .NET 6+ projects. These are not major language redesigns — they are quality-of-life improvements that make code more concise and signal intent more clearly. In a typical ASP.NET Core project, global usings, file-scoped namespaces, and required members together eliminate dozens of repetitive lines per file. Understanding them is important because modern .NET codebases use them universally, and the syntax will appear unfamiliar if you have only worked with older C# versions.
Global Using Directives (C# 10)
// ── Without global usings — every file repeats these imports ──────────────
// PostsController.cs
using System;
using System.Collections.Generic;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using BlogApp.Application.Interfaces;
using BlogApp.Domain.Entities;
// ── With global usings — declared once, apply to entire project ───────────
// GlobalUsings.cs (or any .cs file)
global using System;
global using System.Collections.Generic;
global using System.Linq;
global using Microsoft.AspNetCore.Mvc;
global using Microsoft.Extensions.Logging;
global using BlogApp.Application.Interfaces;
global using BlogApp.Domain.Entities;
// PostsController.cs — now has zero using statements!
// All global usings are available automatically
// ── ImplicitUsings — .NET 6+ automatically adds common BCL namespaces ─────
// In .csproj: <ImplicitUsings>enable</ImplicitUsings>
// Automatically adds: System, System.Linq, System.Collections.Generic,
// System.IO, System.Threading.Tasks, etc.
// For web projects: also Microsoft.AspNetCore.Builder, Http, Routing, etc.
GlobalUsings.cs file at the project root with all custom global usings, making it easy to see and manage what is globally imported.namespace BlogApp.Api; syntax) and block-scoped namespaces (the traditional curly-brace style) cannot be mixed in the same file. Pick one style consistently across the project. Most modern .NET 6+ projects use file-scoped namespaces as they save one level of indentation across every file. Configure your IDE and .editorconfig to enforce the chosen style.File-Scoped Namespaces (C# 10)
// ── Traditional block-scoped namespace — one extra level of indentation ───
namespace BlogApp.Controllers
{
public class PostsController : ControllerBase
{
// All code indented one level under the namespace block
}
}
// ── File-scoped namespace — no indentation overhead ────────────────────────
namespace BlogApp.Controllers; // ← semicolon, applies to entire file
public class PostsController : ControllerBase
{
// Code at top level — no namespace indentation
private readonly IPostService _service;
public PostsController(IPostService service) => _service = service;
[HttpGet("{id:int}")]
public async Task<IActionResult> GetById(int id, CancellationToken ct)
{
var post = await _service.GetByIdAsync(id, ct);
return Ok(post);
}
}
Required Members (C# 11)
// The required modifier — compiler enforces the property must be set during initialisation
public class Post
{
public required int Id { get; init; } // must be set in object initialiser
public required string Title { get; init; } // must be set
public string Body { get; init; } = string.Empty; // optional (has default)
public required string AuthorId { get; init; } // must be set
}
// ✅ Valid — all required properties set
var post = new Post
{
Id = 1,
Title = "Hello World",
AuthorId = "user-42",
// Body is optional — defaults to string.Empty
};
// ❌ Compile error — required property Id not initialised
var bad = new Post { Title = "Hello" }; // compile error: Id is required
Raw String Literals (C# 11)
// At least 3 quotes — no escaping needed inside
string json = """
{
"name": "Alice",
"roles": ["admin", "editor"],
"metadata": { "created": "2025-01-15" }
}
""";
// Combine with interpolation
string name = "Alice";
string jsonInterp = $"""
{{
"name": "{name}",
"timestamp": "{DateTime.UtcNow:O}"
}}
"""; // {{ and }} = literal braces; {expr} = interpolation
Common Mistakes
Mistake 1 — Mixing file-scoped and block-scoped namespaces in one file
❌ Wrong — compile error: cannot mix both styles in one file.
✅ Correct — choose one style project-wide and enforce via .editorconfig.
Mistake 2 — Adding too many namespaces to global usings (naming conflicts)
❌ Wrong — global using Newtonsoft.Json; and global using System.Text.Json; both define JsonSerializer — compiler cannot resolve which one you mean.
✅ Correct — add only the namespace whose type you want to be the default; explicitly qualify the other.