Skip to content

What Is C#? Microsoft's Core Programming Language for .NET

C# is a multi-paradigm Microsoft language: its design goals, the unified .NET platform it runs on, and its evolution through stable version 14.

Tuan Tran Van
13 min read
Contents (10 sections)
  1. What is C#?
  2. C# and .NET: the language, the runtime, and the standard library
  3. What does a first C# program look like?
  4. The static type system: class, struct, record, and generics
  5. Pattern matching, LINQ, and async/await: what makes C# distinct
  6. From COOL to C# 14: more than twenty years of evolution
  7. What do people build with C#? Web, games, mobile, and cloud
  8. How does C# differ from Java?
  9. Where should you start with C#?
  10. References

C# is a general-purpose, high-level, multi-paradigm, and component-oriented programming language developed by Microsoft.

It supports a wide range of programming disciplines, including static typing, strong typing, lexically scoped, imperative, declarative, functional, generic, and object-oriented models. The language leans on software engineering principles that keep a large codebase predictable, and it does all of that inside familiar C-family syntax.

The principal designers of the language were Anders Hejlsberg, Scott Wiltamuth, and Peter Golde. C# first appeared in July 2000 during the official announcement of the .NET project at the Professional Developers Conference. Since its inception, the language has evolved from a Windows-centric tool into a cross-platform international standard, managed through Ecma (ECMA-334) and various ISO/IEC specifications.

C# is the core programming language of the .NET platform, the theme image of this article

What is C#?

C# was built against a specific set of design goals written down in the Ecma standards, and the first of them is that the language be simple, modern, general-purpose, and object-oriented. Unlike assembly or lower-level languages that prioritize raw performance parity, C# emphasizes software engineering principles such as strong type checking, array bounds checking, and the detection of uninitialized variables. On top of that, an automatic garbage collection system manages the memory lifecycle for you, which removes an entire family of manual-cleanup bugs before you can write them.

The language scales in both directions: it suits large hosted systems running full operating systems, and small, dedicated embedded systems. Its design makes it easier to build software components meant for distributed environments. This focus on component-oriented programming lets developers build self-describing, modular units of logic that survive versioning across a large codebase. Scaling in both directions is an easy thing to claim and a hard one to deliver, and it is also why C# keeps ceremony a scripting language would have dropped years ago.

Syntactically, C# belongs to the C-family and shares significant traits with C, C++, and Java. However, it implements a stricter type system to prevent common runtime errors. For example, C# requires a dedicated Boolean data type (bool) for conditional statements, disallowing the "integer meaning true or false" approach found in C++. This prevents errors like accidental assignment within an equality check, ensuring that logic remains predictable and type-safe.

C# and .NET: the language, the runtime, and the standard library

C# rests on the relationship between the language specification and the Common Language Infrastructure (CLI). C# provides the syntax and rules you write against; the CLI specifies the environment the code runs in. Within that infrastructure, the Common Language Runtime (CLR) is the primary implementation, providing the Virtual Execution System (VES) that manages memory, handles exceptions, and enforces security. C# intrinsic types map directly to value-types defined by the CLI, which is why the same value type means the same thing everywhere on the platform.

The path C# code takes: source through the Roslyn compiler into CIL, then CLR and RyuJIT into machine code

The platform moved from the original, closed-source .NET Framework to the modern, open-source, cross-platform unified .NET platform. This unification began with the release of .NET 5.0 and continues through current stable versions. This evolution allows C# applications to target Linux, macOS, and Windows using a single runtime. During this transition, Microsoft open-sourced the primary tooling, including the reference compiler and the runtime components, so development moved somewhere the community could actually reach it.

Two distinct engines handle compilation in the modern .NET era: the Roslyn compiler and RyuJIT. Roslyn is the C# compiler itself, written in managed C# code, and it translates source code into Common Intermediate Language (CIL). A C# compiler written in C# sounds like a stunt, but it is what lets the editor and the build share one engine. RyuJIT is the Just-In-Time (JIT) compiler, written in C++, and it is the execution engine. It converts the CIL into optimized machine code during the program's runtime, performing on-the-fly optimizations tailored to the specific CPU architecture of the host machine.

What does a first C# program look like?

Modern C# favors conciseness through top-level statements, introduced in C# 9. This feature eliminates the boilerplate code traditionally required to establish an entry point. In this format, a "Hello World" application requires only the logic necessary to output to the console, as the compiler automatically synthesizes the surrounding class and method infrastructure.

csharp
Console.WriteLine("Hello, World!");

In contrast, versions of C# prior to 9.0 require a more verbose, explicit structure. This legacy format involves defining a namespace, a class, and a specific static method to serve as the entry point. The following example demonstrates the structure required for C# 8 and earlier, which remains valid in modern versions for complex application configurations.

csharp
using System;
 
class Program
{
    static void Main()
    {
        Console.WriteLine("Hello, World!");
    }
}

The using directive imports namespaces such as System, which contains the Console class. The static void Main method is the designated entry point where the .NET runtime begins execution. The static keyword is a technical requirement for the compiler when processing console applications; it ensures the method is accessible without requiring an instance of the Program class.

From a compiler engineering perspective, if the entry point were not static, the runtime would face an irresolvable circular dependency: it would need to instantiate the class before starting the program, but the instantiation logic itself is part of the program execution. By requiring a static entry point, the Virtual Execution System (VES) can begin execution immediately upon loading the assembly.

The static type system: class, struct, record, and generics

C# employs the Common Type System (CTS), a unified hierarchy where every type — including primitives — is a subclass of System.Object. The system is divided into value types and reference types. Value types, which include primitives (e.g., int, char), structs, and enums, store data directly and are copied when passed as parameters. Reference types, such as classes, interfaces, and strings, store a reference (pointer) to the memory location where the data resides on the heap.

Value types sit on the stack and are copied whole, while reference types sit on the heap and the variable holds only a pointer

The unified nature of the CTS allows for a mechanism called boxing, where a value type is implicitly converted into a reference type so it can be treated as an object. The reverse process, unboxing, requires an explicit type cast to return the reference back to its original value type. While boxing provides flexibility, it introduces performance overhead from heap allocation and type-checking, and a surprising amount of performance work in modern C# is really just some form of avoiding it.

Generics, introduced in C# 2.0, solve the performance and type-safety issues associated with boxing in collections. C# implements generics using reification, which differs from the type erasure used in some other languages. Reified generics mean that type information is preserved at runtime, allowing the JIT compiler to generate optimized machine code specific to the type being used. This ensures that a List<int> is as efficient as a native array, as it avoids the overhead of treating integers as objects.

Pattern matching, LINQ, and async/await: what makes C# distinct

A defining feature of modern C# development is Language Integrated Query (LINQ), which provides a consistent syntax for querying diverse data sources such as SQL databases, XML, and in-memory collections. Developers can choose between query syntax, which resembles SQL, and method syntax, which uses extension methods and lambda expressions. The compiler translates query syntax into method syntax during compilation, so the two perform identically and the choice comes down to which one you can read at speed.

LINQ brings in-memory collections, XML files, and SQL databases under one query syntax inside C#

csharp
using System.Linq;
 
int[] numbers = { 5, 10, 8, 3, 6, 12 };
 
// Query syntax
var numQuery1 = from num in numbers where num % 2 == 0 orderby num select num;
 
// Method syntax
var numQuery2 = numbers.Where(num => num % 2 == 0).OrderBy(n => n);

C# has increasingly integrated functional programming elements to reduce boilerplate and improve logic flow. This includes lambda expressions for anonymous functions and extension methods, which allow developers to add new functionality to existing types without modifying their source code. Pattern matching has also grown well beyond its first version, and it now expresses conditional logic that inspects the shape and data of objects with real precision.

The other feature people name when they talk about C# is its task-driven asynchronous pattern. With the async and await keywords, you write non-blocking code that still reads like ordinary sequential logic. This pattern is essential for scaling web services and maintaining responsive user interfaces, as it allows threads to be released back to the pool while waiting for I/O-bound operations to complete.

From COOL to C# 14: more than twenty years of evolution

The development of C# began in 1999 under the project name COOL (C-like Object Oriented Language). Microsoft considered retaining this name but shifted to "C#" for trademark reasons before the 2000 announcement. The "sharp" suffix is a musical reference indicating a semitone increase in pitch, suggesting that C# is an increment of C++, just as the "++" in C++ suggests an increment of C. Early in its history, C# used a mascot named "Andy" (after Anders Hejlsberg), though this character was officially retired on January 29, 2004.

A timeline of C#: from the COOL project in 1999 through generics, LINQ, async/await, and records, to C# 14 in 2025

The language has followed a consistent release cadence, and each step landed a real technical milestone. C# 2.0 introduced generics; C# 3.0 added LINQ and anonymous types; and C# 9.0 introduced records and top-level statements. Standardization remains a core priority, with early versions (1.0, 2.0, and 5.0) governed by ISO/IEC 23270, while versions 7.0 and later are standardized under ISO/IEC 20619.

The current stable release is C# 14, launched in November 2025. This version targets .NET 10.0 and is supported by Visual Studio 2026 version 18.0. The development of the language specification is now a transparent process hosted on GitHub, allowing the community to participate in language proposals and the evolution of the C# standard.

What do people build with C#? Web, games, mobile, and cloud

C# is the primary scripting language for the Unity game engine, which puts it at the center of the games industry. It handles complex real-time logic, physics, and AI for thousands of titles. The Godot engine provides an optional C# module, further expanding its footprint in game development. Managed memory is usually the first thing people expect to hurt in a game loop, and the thousands of shipped titles are the argument that it does not have to.

Four things people build with C#: web with ASP.NET Core and Blazor, games with Unity, mobile with .NET MAUI, and cloud-native with Native AOT

In web development, C# powers high-performance backends through ASP.NET and ASP.NET Core. These frameworks are used to build scalable APIs and web services that handle millions of requests. For mobile development, C# enables cross-platform application delivery via .NET MAUI (Multi-platform App UI), which allows developers to maintain a single codebase that targets Android, iOS, macOS, and Windows.

The tooling is mature. Microsoft's Visual Studio and Visual Studio Code are the most widely used, providing deep integration with the Roslyn compiler and .NET diagnostic APIs. JetBrains Rider is a prominent alternative, offering specialized cross-platform development features. These tools provide the advanced debugging and profiling capabilities required for large-scale enterprise systems.

How does C# differ from Java?

While C# and Java share common roots, they have diverged significantly in their architectural choices. One of the most notable differences is C#'s omission of checked exceptions. This was a deliberate design decision to improve scalability and version management, avoiding the "fragile base class" problem where adding an exception to a library method can break all downstream implementations.

Generics are another major point of divergence. C# uses reified generics, which maintain type identity at runtime and allow for optimized machine code generation for value types. Java uses type erasure, which removes type information during compilation and often requires boxing value types into objects, potentially impacting performance. Polymorphism is also more explicit in C#; methods are not virtual by default. Developers must use the virtual keyword to permit overrides and the override keyword to implement them, preventing unintended behavior in class hierarchies.

C# compared with Java: C# keeps type information at runtime, while Java erases it after compilation and falls back on wrapper types

C# also provides first-class support for properties, which encapsulate get and set operations into a single named member. This contrasts with the Java convention of using separate getter and setter methods (e.g., setAmount()). C# properties can be virtual, abstract, or auto-implemented, which cuts the boilerplate needed to expose class data safely.

Where should you start with C#?

C# is one of those languages where the sensible starting point is also the least exciting one: a console application, top-level statements, and enough time in the type system to know why a struct behaves differently from a class when you pass it to a method. Boxing is the first thing that will quietly cost you performance, so it is worth understanding properly before you touch a framework.

After that, LINQ and async/await are the two features that change how you write code, and generics is what explains why C# stays fast while doing it. Any of the three main editors works to start with, since Visual Studio, VS Code, and Rider all carry the debugging and profiling tools you will eventually need, and the language specification now lives on GitHub, so when a rule looks arbitrary you can go read the proposal that produced it. If I had to name one reason to learn C# rather than admire it from a distance, it is that a single language and a single runtime cover an ASP.NET Core service, a Unity game, and a .NET MAUI app.

References

Share this article