AlgoMaster Logo

History of C#

Last Updated: May 17, 2026

11 min read

C# started in the late 1990s inside Microsoft as part of a much larger bet called .NET, and the way the language has evolved since then is a steady story of "make everyday code shorter and safer." Knowing the timeline matters because real codebases mix syntax from many eras, and the version a feature shipped in tells you whether you can use it on the project sitting on your desk. This chapter walks from C#'s first prototype in 1999 to C# 13 in 2024, and tracks how .NET itself went from a Windows-only runtime to a cross-platform, open-source one.

Where C# Came From

In the late 1990s, Microsoft started a large internal project to rebuild its developer platform from scratch. The effort was called the .NET initiative, and its goal was to give developers one runtime, one type system, and one set of class libraries that any language could target. As part of that work, Microsoft needed a new flagship object-oriented language designed specifically for the new runtime.

The internal codename for that language was Project Cool. The chief architect was Anders Hejlsberg, who had already designed Turbo Pascal at Borland in the 1980s and led the development of Delphi in the 1990s. He joined Microsoft in 1996, and a few years later he was the lead designer of what would become C#. (Years later he would also kick off TypeScript, which is why if you've used both languages, the family resemblance is real.)

The language was publicly announced in 2000 and shipped with the first release of the .NET Framework in February 2002. From day one, C# was designed to compile to Intermediate Language (IL) and run on the Common Language Runtime (CLR), the same way every other .NET language did. We'll cover the CLR in detail in the .NET Ecosystem lesson, so for now just know that C# was built hand-in-hand with the runtime it targets, not bolted onto an existing one.

In December 2001, even before the official 1.0 release, Microsoft submitted C# to Ecma International for standardization. The language became an open standard as ECMA-334 and the underlying runtime became ECMA-335 (the Common Language Infrastructure). ISO ratified the same documents shortly after. This was a deliberate move: Microsoft wanted C# to be more than a vendor-locked product, and the standard meant other implementations (like the open-source Mono project) could legally build their own C# compilers and runtimes.

C# 1.0 to 3.0: Building the Foundation

C# 1.0 shipped with .NET Framework 1.0 in February 2002. The language had the things you'd expect from an early 2000s object-oriented language: classes, interfaces, structs, enums, properties, delegates, events, exceptions, and a unified type system where everything (even int) ultimately derives from object. It looked enough like other curly-brace languages of the era to be familiar, but the property syntax, the unified type system, and the way value types and reference types coexisted were already distinctly C#.

A minor follow-up, C# 1.2, shipped with .NET Framework 1.1 in 2003. It was mostly small fixes. The first release that really changed how the language felt was C# 2.0.

C# 2.0 (2005, with .NET Framework 2.0) added generics, so List<Product> could carry type information at compile time instead of forcing casts off of a non-generic ArrayList. It also introduced nullable value types (int?), anonymous methods, iterators (the yield return keyword), and partial classes for splitting a class across files. Generics in particular changed every collection-heavy codebase that came after.

C# 3.0 (2007, with .NET Framework 3.5) is the release that gave the language its modern personality. It added LINQ (Language Integrated Query), lambda expressions, the `var` keyword for local type inference, extension methods, object and collection initializers, anonymous types, and expression trees. These features worked together so well that LINQ became one of the defining things people associate with C#.

Here's the kind of one-liner C# 3.0 made possible. Compare it to writing the same query as a manual loop:

The var keyword, the lambda inside Where, and the Select projection are all C# 3.0 additions. Once teams adopted these, the older for (int i = 0; ...) filter loops started looking dated almost overnight.

C# 4.0 to 6.0: Polishing the Developer Experience

C# 4.0 (2010, with .NET Framework 4.0) added the `dynamic` keyword for late-bound member access, named and optional arguments, and improved interop with COM and dynamic languages. The headline feature was dynamic, which let you write code that resolved method calls at runtime instead of compile time. It was useful for Office automation and scripting scenarios but didn't change everyday business code much.

C# 5.0 (2012, with .NET Framework 4.5) is the version that introduced `async` and `await`. Before C# 5, writing asynchronous code in .NET meant callbacks, continuations, or the Task Parallel Library's ContinueWith chains. With async/await, you wrote async code that looked almost exactly like synchronous code, and the compiler rewrote it into a state machine under the hood:

That await keyword and the way the compiler turned an async method into a resumable state machine was a huge productivity unlock. Most modern .NET libraries you'll work with today (HTTP clients, database drivers, file APIs) lean on this model, and the entire ecosystem changed shape around it.

C# 6.0 (2015, with .NET Framework 4.6 and the Roslyn compiler) was a polish release packed with small wins. It introduced string interpolation ($"Hello, {name}"), expression-bodied members for short methods and properties, the null-conditional operator (?.), the `nameof` operator, auto-property initializers, and the `using static` directive. None of these features change what's possible, but together they cut a lot of boilerplate out of everyday code.

A small sample of C# 6.0 style:

C# 6.0 also marked the release of Roslyn, the open-source C# compiler. Before Roslyn, the C# compiler was a closed Microsoft binary. After Roslyn, the compiler became a library that IDEs and tools could call directly. That's why modern C# tooling (IntelliSense, refactoring, analyzers) is as rich as it is.

C# 7 to 9: Pattern Matching, Tuples, and Records

After C# 6, Microsoft moved to a faster release cadence with several point releases between major versions. C# 7.0 (March 2017) added tuples as a real language feature (with named members), pattern matching on is expressions and switch statements, local functions, `out var` declarations, ref returns and locals, and improved numeric literals with digit separators (1_000_000).

Tuples in particular cleaned up a common annoyance: returning multiple values from a method without inventing a one-off struct.

Three point releases followed: C# 7.1 (2017) added async Main and default literal expressions. C# 7.2 (2017) added Span<T>-friendly features like in parameters and readonly structs. C# 7.3 (2018) loosened a handful of constraints on generics and fixed statements. All three were small and shipped alongside Visual Studio updates rather than major .NET releases.

C# 8.0 (September 2019) was a much bigger release and the first version to ship primarily on .NET Core 3.0 rather than .NET Framework. The headline features were nullable reference types, which extend the compiler's null-safety checking to reference types (so string? and string mean different things), default interface methods, async streams (IAsyncEnumerable<T> and await foreach), switch expressions (a more concise form of switch), and using declarations (using var stream = ...;).

The switch expression is one of the most-used additions:

C# 9.0 (November 2020, with .NET 5) introduced records for short data-carrier types with built-in value equality, init-only setters, top-level statements (no more static void Main boilerplate for small programs), pattern matching enhancements, and target-typed `new` expressions.

Records are a clean example. The compiler generates equality, a constructor, deconstruction, and a sensible ToString for you:

That value-based equality on a record is one line of code; the equivalent class with overridden Equals, GetHashCode, ==, and != would be twenty.

C# 10 to 13: Modern C#

C# 10 (November 2021, with .NET 6) was a quieter release focused on cutting boilerplate. It added file-scoped namespaces (namespace ECommerce; at the top of a file, no braces), global usings (one global using System; in a single file applies project-wide), record structs (records that are value types), constant interpolated strings, and improvements to lambdas.

C# 11 (November 2022, with .NET 7) added raw string literals (triple-quoted strings that handle multi-line text and embedded quotes cleanly), required members (properties or fields that must be initialized when an object is created), file-scoped types (a class marked file is only visible in its own file), generic math (numeric interfaces like INumber<T> that let you write algorithms over any numeric type), and list patterns.

Raw strings are particularly handy for JSON, SQL, or any text with quotes inside:

No escape characters, no string concatenation, just the text as you'd want to read it.

C# 12 (November 2023, with .NET 8) added primary constructors for non-record classes and structs (constructor parameters declared right after the class name and usable throughout the body), collection expressions (int[] x = [1, 2, 3];), `alias any type` (you can using an alias for any type, including tuples, arrays, and pointers), default lambda parameters, and inline arrays.

C# 13 (November 2024, with .NET 9) is the current version as of this writing. It introduced `params` collections (so params works with any collection type, not just arrays), the new lock object (System.Threading.Lock for cleaner mutual exclusion), `ref struct` interfaces, partial properties (matching the existing partial-method feature), and several smaller improvements.

Here's the timeline as a diagram. The releases that reshaped how everyday C# code looks are highlighted:

The diagram skips the smaller point releases (C# 1.2, 7.1, 7.2, 7.3) so the bigger inflection points stand out. Here's the same information as a table, including everything, that you can use as a cheat sheet:

VersionYearHeadline Feature(s)
C# 1.02002Initial release with .NET Framework 1.0
C# 1.22003Minor fixes with .NET Framework 1.1
C# 2.02005Generics, nullable value types, iterators, anonymous methods
C# 3.02007LINQ, lambda expressions, var, extension methods, anonymous types
C# 4.02010dynamic, named and optional arguments, COM interop
C# 5.02012async/await
C# 6.02015String interpolation, expression-bodied members, ?., nameof, Roslyn
C# 7.02017Tuples, pattern matching, local functions, out var, ref returns
C# 7.12017Async Main, default literal expressions
C# 7.22017in parameters, readonly structs, Span<T> support
C# 7.32018Generic constraint improvements, fixed improvements
C# 8.02019Nullable reference types, default interface methods, async streams, switch expressions
C# 9.02020Records, init-only setters, top-level statements, target-typed new
C# 102021File-scoped namespaces, global usings, record structs
C# 112022Raw string literals, required members, file-scoped types, generic math
C# 122023Primary constructors, collection expressions, alias any type
C# 132024params collections, new lock object, ref struct interfaces, partial properties

If you only memorize a handful of dates, the rows for 2.0, 3.0, 5.0, 8.0, 9.0, and 11 cover most of what interviewers ask about.

The .NET Evolution

C# only makes sense in the context of the platform it runs on, and that platform has changed significantly over the language's lifetime. The original platform was .NET Framework, released alongside C# 1.0 in 2002. It was Windows-only, shipped with Windows itself, and was the runtime, class libraries, and tooling all rolled together. Versions went 1.0, 1.1, 2.0, 3.5, 4.0, 4.5, all the way through to 4.8 (the final .NET Framework release in 2019). Many enterprise systems still run on .NET Framework today.

The big shift started in 2014, when Microsoft open-sourced .NET and launched the independent .NET Foundation to steward the open-source codebases. The Roslyn compiler, the core libraries, and eventually the entire runtime were moved to GitHub under permissive licenses. That single decision changed the trajectory of the platform.

Two years later, in June 2016, Microsoft released .NET Core 1.0: a cross-platform, open-source, modular reimplementation of .NET that ran on Windows, Linux, and macOS. .NET Core was a hard break from .NET Framework in places (a smaller class library, no WinForms or WPF initially), but it solved the biggest single complaint about C#: that you couldn't ship a production server on Linux without third-party effort. .NET Core 2.0, 2.1, 3.0, and 3.1 (the first LTS) followed quickly through 2017 to 2019.

In November 2020, Microsoft did the next big consolidation: it released .NET 5, dropping the "Core" suffix and announcing that this single, unified .NET would replace both .NET Framework and .NET Core going forward. From .NET 5 onward, there's just one .NET, cross-platform by default, open-source, and on a predictable annual release cadence (a new major version every November).

The diagram shows the three eras: the original Windows-only .NET Framework, the cross-platform .NET Core years, and the unified .NET that we have today. .NET 8 is the current LTS (long-term support, three years of patches), and .NET 9 is the latest annual release.

A small detail worth knowing: .NET LTS releases ship on even-numbered years (.NET 6, .NET 8, .NET 10), and they're what most production teams target. Odd-numbered releases (.NET 7, .NET 9) are supported for 18 months and are mainly useful for previewing what's coming next. If you're starting a new project today, the right default is the most recent LTS that your tooling supports.

Even a small program today goes through the same compile-to-IL, run-on-CLR flow that C# 1.0 used in 2002. The surface of the language has changed dramatically, but the underlying execution model is the same:

That code uses C# 9 top-level statements and C# 6 string interpolation, but it would translate cleanly to C# 1.0 syntax. Backward compatibility has been a deliberate priority, and most C# code from any era still compiles on the current compiler with very few changes.

Summary

  • C# was designed at Microsoft in the late 1990s by Anders Hejlsberg (codename "Project Cool") and shipped with .NET Framework 1.0 in 2002.
  • The language is an open standard: ECMA-334, ratified by ISO and matched by the runtime spec ECMA-335.
  • C# 2.0 (2005) added generics. C# 3.0 (2007) added LINQ, lambdas, var, and extension methods, giving the language its modern personality.
  • C# 5.0 (2012) introduced async/await, reshaping how async code is written across the entire .NET ecosystem.
  • C# 8.0 (2019) added nullable reference types, switch expressions, and async streams. C# 9.0 (2020) added records and top-level statements.
  • Recent versions (C# 10 through 13) have focused on cutting boilerplate: file-scoped namespaces, global usings, raw string literals, required members, primary constructors, and collection expressions.
  • .NET itself went from Windows-only .NET Framework (2002), to open-sourced in 2014, to cross-platform .NET Core 1.0 in 2016, to unified .NET 5 in 2020, with annual releases since. .NET 8 is the current LTS.
  • Backward compatibility has been a priority, so most older C# code still compiles cleanly on the current compiler.

Now that we know the timeline, the next lesson covers the major features that make C# what it is today.