Attributes and reflection
C# 1.0 NETFx 4.5
Attributes add metadata to code, and reflection reads that metadata back when you need lightweight discovery.
Follow each language release as its own shelf of guides, then branch into full articles and related features from there.
Browse all features → · Browse by theme → · See the timeline →
C# 1.0 NETFx 4.5
Attributes add metadata to code, and reflection reads that metadata back when you need lightweight discovery.
C# 3.0 NETFx 3.5
Use var for obvious local types and anonymous types while keeping compile-time static typing.
C# 3.0 NETFx 3.5
Anonymous types let you create lightweight objects on the fly with new { property = value } syntax. The compiler generates a class for you with equality and ToString() built in.
C# 3.0 NETFx 3.5
Auto-implemented properties let you declare a property with just { get; set; }, letting the compiler generate the backing field for you. They cut property boilerplate while keeping your intent crystal clear.
C# 3.0 NETFx 3.5
Extension methods let you add discoverable helpers to existing types, which is why they show up everywhere from LINQ to application-specific fluent APIs.
C# 3.0 NETFx 3.5
Use built-in generic delegate types to pass behavior without defining one-off delegate types.
C# 3.0 NETFx 3.5
Lambda expressions make delegate-based code shorter and easier to scan, especially when you pass behavior into LINQ, events, and async APIs.
C# 3.0 NETFx 3.5
LINQ gives C# a consistent way to filter, transform, group, and sort data with either query syntax or fluent method syntax.
C# 3.0 NETFx 3.5
Object and collection initializers let you populate properties and collection elements inline at construction time. Instead of creating an object and then setting properties separately, you do it all in one readable expression.
C# 4.0 NETFx 4.5
Named arguments and default values make APIs easier to read without multiplying overloads.
C# 5.0 NETFx 4.5
async and await make asynchronous code read like straight-line code while still freeing threads during I/O waits.
C# 6.0 NETFx 4.6
Exception filters let you catch only the failures you actually know how to handle.
C# 6.0 NETFx 4.6
Expression-bodied members let you define methods, properties, and accessors using arrow syntax (=>) instead of braces and return statements, reducing boilerplate and improving readability for simple logic.
C# 6.0 NETFx 4.6
Use string interpolation ($"...") to build readable strings without manual concatenation.
C# 6.0 NETFx 4.6
using static imports static members so formulas and focused helper APIs read without type-name repetition.
C# 7.0 NETFx 4.7
Local functions are methods defined inside other methods or properties, letting you encapsulate helper logic at the point of use. They reduce namespace clutter, improve readability by keeping related logic together, and naturally capture variables from their enclosing scope.
C# 7.0 NETFx 4.7
Ref returns hand back a reference to existing storage so callers can work in place instead of through a copy.
C# 7.0 NETFx 4.7
Tuples provide a lightweight syntax for grouping related values together and deconstruction enables you to unpack tuple elements into individual variables.
C# 7.2 NETCore 2.1
Control argument passing by reference to return extra values, mutate callers, or avoid copies for readonly inputs.
C# 7.2 NETCore 2.1
ref struct types stay on the stack, which makes span-heavy APIs safe and allocation-conscious.
C# 7.2 NETCore 2.1
Work with contiguous memory efficiently using safe slices that avoid many temporary allocations.
C# 8.0 NETCore 3.0
Async streams pair IAsyncEnumerable<T> with await foreach so asynchronous producers can yield values progressively instead of buffering everything first.
C# 8.0 NETCore 3.0
Evolve interfaces by adding members with default implementations so existing implementers do not break immediately.
C# 8.0 NETCore 3.0
The null coalescing operator (??) and null coalescing assignment operator (??=) provide concise ways to handle null values, letting you specify fallback values or conditionally assign without verbose null checks.
C# 8.0 NETCore 3.0
Nullable reference types make nullability part of the type system, which helps the compiler catch bugs before they reach production.
C# 8.0 NETCore 3.0
Range (…) and index (^) operators provide concise syntax for accessing array elements and extracting subsequences. The index operator lets you count from the end; the range operator extracts contiguous slices without manual offset calculations.
C# 8.0 NETCore 3.0
Dispose resources automatically with less indentation and cleaner control flow than traditional using blocks.
C# 8.0 .NET 5.0
Switch expressions bring functional-style pattern matching to C# as lightweight expressions that replace traditional switch statements with cleaner, more concise code.
C# 9.0 .NET 5.0
Init accessors let you keep object initialization simple while still protecting properties from later mutation.
C# 9.0 .NET 5.0
Pattern matching gives C# a precise branching model for types, values, and shapes, which makes complex decisions easier to read.
C# 9.0 .NET 5.0
Records are a concise way to model value-oriented data with built-in equality, deconstruction, and non-destructive mutation.
C# 9.0 .NET 5.0
Write C# code at the file level without wrapping in a class and Main method, making simple programs feel less boilerplate-heavy.
C# 9.0 .NET 5.0
With expressions let you copy immutable data and update only what changed, keeping your intent crisp and your models predictable.
C# 10.0 .NET 6.0
File-scoped namespaces declare a namespace at the file level with a simple semicolon syntax, eliminating unnecessary indentation and making code cleaner and easier to read.
C# 10.0 .NET 6.0
Global using directives allow you to specify imports that automatically apply to all files in your project, reducing repetitive using statements and improving code organization at scale.
C# 10.0 .NET 6.0
nameof and CallerArgumentExpression help your APIs report exactly what went wrong, with refactor-safe names and call-site expressions.
C# 11.0 .NET 7.0
File-local types (file class, file record, and similar declarations) keep implementation-only types visible to one source file.
C# 11.0 .NET 7.0
Match specific positions and elements in arrays or lists using patterns, reducing complex index-based conditionals to readable, declarative expressions.
C# 11.0 .NET 7.0
Raw string literals are delimited by three or more quotes and eliminate escape-sequence processing, making it easy to work with JSON, SQL, and multiline text.
C# 11.0 .NET 7.0
Required members enforce that specific properties must be set during object initialization, preventing incomplete objects and catching errors at compile time.
C# 11.0 .NET 7.0
Define compile-time contracts for static members so generic algorithms can call them safely.
C# 12.0 .NET 8.0
Use a unified, concise syntax to initialize arrays, lists, spans, and other collections with cleaner code and optional spread operators for composition.
C# 12.0 .NET 8.0
Declare constructor parameters directly in the class declaration, eliminating the need for explicit constructor bodies and field assignments.