Skip to main content
SEMastery
.NET Corebeginner

New Features in C# 13: A Friendly Beginner's Guide

Learn the new features in C# 13 with simple words, real-life examples, diagrams, and code you can read in minutes. Great for beginners.

11 min readUpdated April 22, 2026

C# keeps growing every year. Each new version adds small tools that make your code shorter, safer, and easier to read. C# 13 came out with .NET 9, and it has some really handy gifts for us.

In this guide we will walk through the main new features one by one. We will use simple words and small examples. By the end, you will know what changed and why it matters.

A real-life way to think about it

Imagine your mother is cooking in the kitchen. She has a steel tiffin box. Earlier, this box could only hold rice. If she wanted to carry dal, she needed a different container. That was a rule, and it was a bit annoying.

Now imagine someone improves the tiffin box so it can hold rice, dal, sabzi, or even just one roti. Same box, but it accepts many kinds of food. Your mother does not change how she packs lunch. The box just became more flexible.

C# 13 is a lot like that improved tiffin box. Many features take something that already worked, and make it accept more cases or work more safely. You do not throw away what you know. You just get more room to move.

Let us see how the language grew this year.

C# 13 adds flexible, safe tools on top of what you already know

Feature 1: params collections

You may have used the params keyword before. It lets a method accept any number of arguments. Here is the old style.

// Old way: params only worked with an array
void PrintNames(params string[] names)
{
    foreach (var name in names)
    {
        Console.WriteLine(name);
    }
}
 
PrintNames("Asha", "Ravi", "Meena"); // works fine

The catch is that params only worked with arrays. Arrays are fine, but they always create a new block of memory. Sometimes you want something lighter, like a Span<T> or a ReadOnlySpan<T>, which can avoid extra memory work.

In C# 13, params now works with many collection types. You can use spans, lists, and any type that the compiler knows how to build.

// New in C# 13: params works with Span and other collections
void PrintNames(params ReadOnlySpan<string> names)
{
    foreach (var name in names)
    {
        Console.WriteLine(name);
    }
}
 
PrintNames("Asha", "Ravi", "Meena"); // same call, lighter under the hood

Why does this help? When you use a ReadOnlySpan<string> here, the compiler can often skip creating a full array on the heap. That means less memory pressure and faster code in hot paths. The nice part is that the person calling your method does not see any difference. They still write the same simple call.

Here is a quick comparison.

PointOld params (array)New params collections
Allowed typesOnly arraysArrays, spans, lists, and more
Memory costAlways allocates an arrayCan avoid heap allocation
Call site codeSame simple callSame simple call
Best forGeneral usePerformance-sensitive code

Feature 2: the new lock object

When many tasks run at the same time, they can fight over the same data. To stop the fight, we use a lock. It is like a single bathroom key in a hostel. Only one person can hold the key at a time, so only one person enters.

For years, C# used the lock keyword on a plain object. Behind the scenes it used a class called Monitor. It worked, but it was not made for this job from the start.

.NET 9 adds a brand new type made just for locking: System.Threading.Lock. The C# 13 compiler is smart. When you lock on a Lock object, it quietly uses the new, faster API.

using System.Threading;
 
public class BankAccount
{
    // New dedicated lock type from .NET 9
    private readonly Lock _balanceLock = new();
    private decimal _balance;
 
    public void Deposit(decimal amount)
    {
        lock (_balanceLock)   // compiler uses the new Lock API
        {
            _balance += amount;
        }
    }
}

Notice how little changed. You used to write private readonly object _balanceLock = new();. Now you write Lock instead of object. The lock block looks the same. That is the whole point. You get a cleaner, faster lock by changing one word.

There is also a method called EnterScope() for people who like the using pattern.

public void Deposit(decimal amount)
{
    using (_balanceLock.EnterScope())
    {
        _balance += amount;
    }
}

The diagram below shows how one task waits while another holds the key.

Only one task can hold the lock at a time

How the new lock works

Enter
Work
Release

Steps

1

Enter

Take the lock

2

Work

Change shared data safely

3

Release

Free the lock for others

Enter, do the work, then release

Feature 3: partial properties and indexers

You may already know partial classes. They let you split one class across two files. This is very common when a tool generates part of your code (like a source generator), and you write the rest by hand.

Before, you could split methods this way. In C# 13, you can also split properties and indexers.

The idea has two parts: a declaring part that says "this property exists," and an implementing part that says "here is how it works."

// File 1: generated by a tool
public partial class Person
{
    public partial string FullName { get; set; }
}
 
// File 2: written by you
public partial class Person
{
    private string _name = "";
 
    public partial string FullName
    {
        get => _name;
        set => _name = value.Trim();
    }
}

One rule to remember: the implementing part cannot be a simple auto-property like { get; set; }. It must have a real body, as shown above. This keeps things clear about which part is the "real" code.

This feature mostly helps library authors and code generators. As a beginner, you may not write this every day. But when you see it in a generated file, you will now know what it means.

Feature 4: the new escape sequence \e

This one is small but fun. In text, some characters are special and need an "escape." For example, \n means a new line and \t means a tab.

C# 13 adds \e. It stands for the ESCAPE character (Unicode U+001B). This character is used to send special commands to a terminal, like making text bold or colored using ANSI codes.

// \e is the new escape character in C# 13
Console.WriteLine("\e[1mThis text is bold\e[0m");
Console.WriteLine("\e[31mThis text is red\e[0m");

Before C# 13, people wrote  or \x1b to get the same character. Those worked, but \x1b could sometimes cause confusing bugs because it greedily reads extra characters. The new \e is short, clear, and safe.

Feature 5: ref struct can do more

This part is a little more advanced, so do not worry if it feels new. A ref struct is a special kind of struct that must live on the stack. Span<T> is the most famous example. It is fast, but it had many rules about where you could use it.

C# 13 relaxes several of these rules. Here is a friendly table of what changed.

Change in C# 13What it means for you
ref struct can implement interfacesYour span-like types can promise behavior, like IDisposable
allows ref struct in genericsA generic method can accept a ref struct type argument
ref struct in async and iteratorsYou can use spans more freely (not across an await)
ref locals in async methodsMore room to write fast code

A small taste of the generics part looks like this.

// "allows ref struct" lets T be a ref struct like Span<T>
public void Process<T>(T value)
    where T : allows ref struct
{
    // T can now be Span<int>, ReadOnlySpan<char>, etc.
    Console.WriteLine("Processing a value");
}

You will not use these every day as a beginner. But it is good to know the language is removing old limits so advanced, fast code becomes easier to write.

ref struct restrictions are loosened in C# 13

Feature 6: other small touches

C# 13 also brings a few smaller improvements that are nice to know:

  • Implicit index access in object initializers. You can use the ^ (from-the-end) index when setting up array items inside an object initializer.
  • Lock works with using. As we saw, EnterScope() plays well with the using statement.
  • Better overload resolution in some params cases, so the compiler picks the best method more often.

None of these will change your daily code much, but together they make the language feel smoother.

Putting it all together

Let us look at one tiny example that uses two of the new features at once: the new Lock type and params collections.

using System.Threading;
 
public class Logger
{
    private readonly Lock _gate = new();
 
    // params collection: accepts any number of messages cheaply
    public void Log(params ReadOnlySpan<string> messages)
    {
        lock (_gate)
        {
            foreach (var message in messages)
            {
                Console.WriteLine($"[LOG] {message}");
            }
        }
    }
}
 
var logger = new Logger();
logger.Log("App started", "User signed in", "Data loaded");

This small class is safe across threads (thanks to Lock) and light on memory (thanks to the span-based params). And it is still very easy to read.

Your path to learning C# 13

Update SDK
Try one feature
Read the docs
Build something

Steps

1

Update SDK

Install .NET 9

2

Try one feature

Maybe params or Lock

3

Read the docs

Microsoft Learn is your friend

4

Build something

Practice makes it stick

Start small, add more later

How to start using C# 13

Getting C# 13 is easy. You need .NET 9 installed. When your project targets net9.0, the compiler uses C# 13 by default. You usually do not need to set anything by hand.

If you ever need to be sure, you can add this line to your project file:

// In your .csproj file
// <LangVersion>13</LangVersion>

After that, just write code as usual. The new features are there waiting for you.

A quick note for the curious: the .NET world keeps moving. .NET 10 is now the long-term support release, and C# 14 has already shipped with even more goodies. C# 15 is bringing union types in the .NET 11 preview. But everything you learn in C# 13 still works in the newer versions. Learning C# 13 well is a strong base for the future.

Quick recap

  • params collections let params accept spans and other collections, not just arrays. This can save memory.
  • The new System.Threading.Lock type gives you faster, cleaner locking. Just change object to Lock.
  • Partial properties and indexers let you split a property across files, which helps code generators.
  • The \e escape sequence is a short, safe way to write the ESCAPE character for terminal colors and styles.
  • ref struct types gained new powers: they can implement interfaces, be used in generics with allows ref struct, and appear in async and iterator methods.
  • A few small touches like index access in object initializers make the language smoother.
  • To use it all, target .NET 9. The compiler picks C# 13 for you.

You do not have to memorize everything. Pick one feature, try it in a small program, and let it sink in. That is how every good developer learns.

References and further reading

Related Posts