C# and .NET
|
This section documents C# 14 on .NET 10 (LTS), as published at learn.microsoft.com/dotnet/csharp, which is the reference these pages are written and verified against. Features introduced by C# 15 / .NET 11 are still in preview and are always flagged as such — never presented as baseline. This content was generated with the assistance of AI and should be verified against learn.microsoft.com before being relied on in production. This section’s bibliography lists the reference material consulted while preparing these pages. |
C# is a language; .NET is the platform it targets. The language specification defines syntax and semantics, but
almost everything you actually call — Console, List<T>, Task, string — comes from .NET’s class
library, and everything you run is executed by a .NET runtime. Knowing where the boundary lies explains a lot:
why int and System.Int32 are the same type, why async needs no runtime support beyond Task, and why a
language feature can ship only when the runtime is ready for it.
Managed Execution and the CLR
The Common Language Runtime is the execution engine. Compiling produces IL (intermediate language) plus metadata; the CLR loads that and provides:
-
JIT compilation — IL is compiled to native code method by method, on first call. Tiered compilation compiles quickly at first (tier 0) and then recompiles hot methods with full optimisation (tier 1), using profile data gathered from the running program (dynamic PGO).
-
Automatic memory management — a generational, compacting garbage collector. See Memory Management and Disposal.
-
Type safety and verification — the runtime enforces that IL respects the type system.
-
Exception handling, threading, reflection and interop services.
"Managed code" simply means code the CLR executes and whose memory it owns. unsafe blocks and P/Invoke step
outside that guarantee deliberately; see
Unsafe Code, Spans and Performance and
Native Interop.
Native AOT is the alternative: dotnet publish -p:PublishAot=true compiles the whole application ahead of
time into a self-contained native executable with no JIT and no IL at run time. Startup is near-instant and
memory use drops, at the cost of dynamic capabilities — runtime code generation and unbounded reflection are
not available, and the whole program must be statically analysable for trimming.
Assemblies and Metadata
An assembly is the unit of deployment, versioning and (with internal) accessibility: a .dll or .exe
holding IL, metadata and resources. Metadata is a complete, machine-readable description of every type and
member in the assembly — which is why C# needs no header files, why IntelliSense works against a compiled
library, and why reflection can enumerate types it has never seen before.
using System.Reflection;
Assembly assembly = typeof(string).Assembly;
Console.WriteLine(assembly.FullName); // System.Private.CoreLib, Version=10.0.0.0, ...
Console.WriteLine(assembly.Location); // path to the loaded file
// Metadata is queryable at run time.
foreach (MethodInfo method in typeof(string).GetMethods(BindingFlags.Public | BindingFlags.Static)
.Take(3))
{
Console.WriteLine(method.Name);
}
See Namespaces, Assemblies and Projects for how assemblies are produced and referenced, and Attributes and Reflection for reading metadata.
The Base Class Library
The BCL is the standard library every .NET language shares. The C# language keyword int is an alias for the
BCL type System.Int32 — they are interchangeable, and int.MaxValue and System.Int32.MaxValue are the same
member:
int a = 42;
System.Int32 b = 42;
Console.WriteLine(a == b); // True -- the same type
Console.WriteLine(typeof(int) == typeof(System.Int32)); // True
The same holds for string/String, bool/Boolean, object/Object and the rest. The house convention
(and Microsoft’s) is to use the C# keyword when referring to the type and the framework name when calling a
static member, e.g. int.Parse is written int.Parse, not Int32.Parse.
The Runtimes
| Runtime | What it is |
|---|---|
.NET 10 |
The current cross-platform runtime — the one these pages assume. Successor to .NET Core; runs on Windows, Linux, macOS, and (through workloads) Android, iOS and WebAssembly. |
.NET Framework 4.8.1 |
The original Windows-only runtime. Still supported as a component of Windows, but frozen — it receives no new language or library features. Maximum practical language version is C# 7.3. |
Mono |
The runtime used for Android, iOS, and Blazor WebAssembly, shipped as part of .NET and selected automatically by the relevant workload. |
Blazor WebAssembly |
.NET compiled to run inside the browser’s WebAssembly sandbox, with an optional AOT mode for hot paths. |
Support Policy: LTS and STS
Releases alternate. LTS (even-numbered: .NET 8, .NET 10) are supported for three years; STS (odd-numbered: .NET 9, .NET 11) for 18 months. Both are production-quality; the difference is only the support window. .NET 10 was released in November 2025 and is supported into November 2028.
Target Framework Monikers and Language Versions
A project declares what it targets with a TFM:
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
</PropertyGroup>
Platform-specific TFMs add an OS and optionally a version: net10.0-windows, net10.0-android,
net10.0-ios18.0. A library can multi-target:
<PropertyGroup>
<TargetFrameworks>net10.0;net8.0;netstandard2.0</TargetFrameworks>
</PropertyGroup>
The TFM also picks the default language version. net10.0 defaults to C# 14, net9.0 to C# 13, net8.0 to
C# 12, and netstandard2.0 to C# 7.3. Setting <LangVersion> explicitly is supported but only lowers risk in
one direction: features that need runtime or library support (records need IsExternalInit, required needs
RequiredMemberAttribute, generic math needs static abstract interface members) will not work on an older TFM
just because the compiler accepts the syntax.
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<LangVersion>preview</LangVersion> <!-- opt into C# 15 preview features -->
</PropertyGroup>
|
Preview features (C# 15 / .NET 11)
Everything in this section labelled C# 15 preview requires a .NET 11 preview SDK and
|
.NET Standard: The Legacy Bridge
netstandard2.0 is a specification of APIs, not a runtime — a way for one library to be consumed by .NET
Framework, Mono and .NET Core alike. It was superseded by the unified net<version> TFMs, and new libraries
should target net10.0 (adding netstandard2.0 only if .NET Framework consumers still matter). .NET Standard
2.1 was never implemented by .NET Framework, which is why 2.0 is the practical floor for that scenario.
Interoperating with F# and Visual Basic
All .NET languages compile to the same IL and share the same type system, so a C# project can reference an F# or VB project directly and call its types with no shim. A few practical notes:
-
F# records, discriminated unions and functions surface to C# as classes and
FSharpFuncvalues; the[<CLIMutable>]and module attributes control how friendly that surface is. -
VB’s late binding (
Option Strict Off) maps to C#'sdynamic. -
The Common Language Specification (CLS) defines the subset of the type system every language must understand. Marking a public API
[assembly: CLSCompliant(true)]makes the compiler warn about members — unsigned types in public signatures, identifiers differing only in case — that other languages could not consume.
See Also
-
Getting Started — installing the SDK and building a first project.
-
Namespaces, Assemblies and Projects — multi-targeting, NuGet, trimming and deployment models.
-
Memory Management and Disposal — the garbage collector this runtime provides.
-
C# Versions and What’s New — which language version goes with which release.
References
-
github.com/dotnet/runtime — the runtime and class library source.