Your country

Tools that support it use your country for local currency, number formats, units and paper size. Your choice is saved only in this browser.

Type a name or a two-letter code. Use the up and down arrow keys to move through the countries, Enter to choose one and Escape to close.

C# & .NET (C# 14, .NET 10 LTS)  Module 6 – Classes, objects and encapsulation

Extension methods and C# 14 extension members

Write classic C# extension methods and C# 14 extension blocks with properties, static members and operators, and predict which member a call reaches.

  • Intermediate
  • 20 minutes
  • Examples run with .NET 10.0.401 and Python 3.14.8
  • By MySmartCoPilot
Free core, Pro depth: 8 of 20 minutes free
Free: An extension method is a static method that reads like a member · C# 14 extension blocks add properties, static members and operators · Instance members always win, and extensions see no private members. With a pass: 3 in-depth parts and 3 interview answers, about 12 minutes.

What you will learn

  • Write classic extension methods and C# 14 extension blocks
  • Add extension properties, static extension members and operators to types you do not own
  • Predict which member a call binds to when a type and an extension both offer it, now and after a library update
  • Design extensions for structs and for values they cannot store, with ref receivers and the right storage
  • Decide when an extension is clearer than a static helper, an instance member or a new type

Before you start

What you’ll learn · Before you start

What you will learn

  • Write classic extension methods and C# 14 extension blocks
  • Add extension properties, static extension members and operators to types you do not own
  • Predict which member a call binds to when a type and an extension both offer it, now and after a library update
  • Design extensions for structs and for values they cannot store, with ref receivers and the right storage
  • Decide when an extension is clearer than a static helper, an instance member or a new type

Before you start

On this page

"4512398760".Masked() returns ******8760, yet string has no Masked method: an extension declared it from outside the type. LINQ’s Where, Select and Count reach every array and list the same way, and C# 14 lets extensions add properties, static members and operators too.

You will write classic extension methods and C# 14 extension blocks, predict which member a call reaches, and decide when an extension is the clearest design.

An extension method is a static method that reads like a member

An extension method: A static method of a static class whose first parameter is marked this, such as WordCount(this string text). Callers write text.WordCount(), and the compiler turns the call into TextExtensions.WordCount(text). is a static method in a static class that is neither nested nor generic, with this before its first parameter. A using directive for its namespace brings it into scope:

classic.cs: two extension methods for string C# · classic/classic.cs
using Rail.Text;

// A classic extension method: a static method whose first parameter carries this, called as if string had it.
var pnr = "4512398760";
Console.WriteLine($"pnr.Masked():               {pnr.Masked()}");
Console.WriteLine($"TextExtensions.Masked(pnr): {TextExtensions.Masked(pnr)}");

// The call is a static method call, so a null receiver arrives as an argument instead of throwing.
string? missing = null;
Console.WriteLine($"missing.IsBlank():          {missing.IsBlank()}");

namespace Rail.Text
{
    // Extension methods live in a static class that is not nested and not generic.
    public static class TextExtensions
    {
        // Every character but the last four becomes *, as on a ticket shared in a screenshot.
        public static string Masked(this string text) =>
            text.Length <= 4 ? text : new string('*', text.Length - 4) + text[^4..];

        public static bool IsBlank(this string? text) => string.IsNullOrWhiteSpace(text);
    }
}

Output

pnr.Masked():               ******8760
TextExtensions.Masked(pnr): ******8760
missing.IsBlank():          True

Recorded with .NET SDK 10.0.401 (runtime 10.0.12) on macOS 26 arm64. To run it yourself: dotnet run classic.cs

pnr.Masked() and TextExtensions.Masked(pnr) both printed ******8760, because the compiler turns the first into the second: extension methods are static methods called with instance syntax. That explains the last line: IsBlank on a null string returned True without an exception, because the string was passed as an argument and no member of a null object was called.

You write The compiler calls
pnr.Masked() TextExtensions.Masked(pnr)
missing.IsBlank() TextExtensions.IsBlank(missing), with null as the argument

Extension methods arrived in C# 3.0 with LINQ, whose query operators are extension methods on IEnumerable<T>: using System.Linq is what puts Where on every array.

Checkpoint

Check: Classic extension methods

  1. Question 1 of 2 What does the compiler turn pnr.Masked() into in classic.cs?

    Choose one answer.

    Show the answer: Question 1 of 2

    Answer: TextExtensions.Masked(pnr)

    Both lines of the run printed ******8760 because they are the same call: the receiver becomes the first argument.

  2. Question 2 of 2 string? missing = null; What does missing.IsBlank() do?

    Choose one answer.

    Show the answer: Question 2 of 2

    Answer: It returns True, because null is passed to IsBlank as an argument

    A classic extension method can handle a null receiver on purpose, as IsBlank does; one that dereferences it throws inside the method instead.

C# 14 extension blocks add properties, static members and operators

C# 14 extension members are declared in an extension block: A C# 14 declaration, extension(Type receiver) { … }, inside a static class. Its members become extension methods, extension properties and operators of that type; a block that names only the type, extension(Type), declares static extension members., extension(...) { }, inside the same kind of static class. blocks.cs gives sequences of boarding counts three new members and keeps a classic extension method beside them:

blocks.cs: a property, a static method and an operator for sequences C# · blocks/blocks.cs
using Rail.Boarding;

// C# 14 extension blocks give sequences of boarding counts an instance property, a static method and an operator,
// next to a classic extension method. Callers use them as if IEnumerable<int> had declared them.
IEnumerable<int> morning = [5, 3, 8];
IEnumerable<int> evening = [2, 6, 1];

Console.WriteLine($"morning.Total: {morning.Total}, evening.Total: {evening.Total}");
Console.WriteLine($"IEnumerable<int>.Zeros(3): {string.Join(", ", IEnumerable<int>.Zeros(3))}");
Console.WriteLine($"morning + evening: {string.Join(", ", morning + evening)}");
Console.WriteLine($"morning.Busiest(): {morning.Busiest()}");

namespace Rail.Boarding
{
    public static class BoardingExtensions
    {
        // A receiver with a name: instance members, which read counts.
        extension(IEnumerable<int> counts)
        {
            public int Total => counts.Sum();
        }

        // A receiver type only: static members and operators of IEnumerable<int>.
        extension(IEnumerable<int>)
        {
            public static IEnumerable<int> Zeros(int stations) => Enumerable.Repeat(0, stations);

            // Station by station: the boardings of two trains added together.
            public static IEnumerable<int> operator +(IEnumerable<int> left, IEnumerable<int> right) =>
                left.Zip(right, (a, b) => a + b);
        }

        // A classic extension method in the same class: the two forms compile to the same kind of static method.
        public static int Busiest(this IEnumerable<int> counts) => counts.Max();
    }
}

Output

morning.Total: 16, evening.Total: 9
IEnumerable<int>.Zeros(3): 0, 0, 0
morning + evening: 7, 9, 9
morning.Busiest(): 8

Recorded with .NET SDK 10.0.401 (runtime 10.0.12) on macOS 26 arm64. To run it yourself: dotnet run blocks.cs

The first block names its receiver: The value an extension member works on: the this parameter of an extension method, or the named parameter of an extension block, such as source in extension<T>(IEnumerable<T> source)., counts, and declares members that callers reach through a value: morning.Total was 16 and evening.Total 9. The second block names only the type, so its members are static members of IEnumerable<int>: IEnumerable<int>.Zeros(3) gave 0, 0, 0, and morning + evening added the two trains station by station, 7, 9, 9. C# 14 extension members and classic extension methods compile to the same kind of static method, so Busiest() sits in the same class, and converting one form to the other changes no call site.

Declared in Declares Callers write
extension(IEnumerable<int> counts) instance methods and properties morning.Total
extension(IEnumerable<int>) static members and operators IEnumerable<int>.Zeros(3), morning + evening
static int Busiest(this IEnumerable<int> counts) an instance method only morning.Busiest()

C# 15 adds extension indexers

From C# 15, says the language reference, a block with a named receiver may also declare indexers, such as numbers[2]. C# 15 is in preview with .NET 11; this lesson’s examples run on C# 14.

Checkpoint

Check: C# 14 extension blocks

  1. Question 1 of 2 You want callers to write IEnumerable<int>.Zeros(3), on the type itself. Where do you declare Zeros?

    Choose one answer.

    Show the answer: Question 1 of 2

    Answer: In extension(IEnumerable<int>) { public static IEnumerable<int> Zeros(int stations) => Enumerable.Repeat(0, stations); }

    The receiver decides the kind of member: a named receiver for instance members, a type alone for static members and operators.

  2. Question 2 of 2 In blocks.cs, morning holds 5, 3 and 8, and evening holds 2, 6 and 1. What did morning + evening produce?

    Choose one answer.

    Show the answer: Question 2 of 2

    Answer: 7, 9, 9

    Extension operators let a type you do not own take part in expressions, as user-defined operators do.

Instance members always win, and extensions see no private members

An extension can add to a type, never replace what the type already has. wins.cs gives Ticket an extension Describe() with the same signature as its own method, and an extension property that reads the ticket’s fare:

wins.cs: an instance method, an extension with its name, and a property C# · wins/wins.cs
using Rail.Tickets;

// An extension never replaces a member that the type already has, and it reaches only what any other code can.
var ticket = new Ticket("4512398760", 2_150_00);
Console.WriteLine($"ticket.Describe():                 {ticket.Describe()}");
Console.WriteLine($"TicketExtensions.Describe(ticket): {TicketExtensions.Describe(ticket)}");
Console.WriteLine($"ticket.FareInRupees:               {ticket.FareInRupees}");

namespace Rail.Tickets
{
    public sealed class Ticket(string pnr, int farePaise)
    {
        public int FarePaise => farePaise;

        public string Describe() => $"ticket {pnr}";
    }

    public static class TicketExtensions
    {
        extension(Ticket ticket)
        {
            // Same name and parameters as Ticket.Describe, so ticket.Describe() never reaches it.
            public string Describe() => $"a ticket of {ticket.FarePaise} paise";

            // ticket.pnr would not compile here: an extension sees the public members, as any other code does.
            public decimal FareInRupees => ticket.FarePaise / 100m;
        }
    }
}

Output

ticket.Describe():                 ticket 4512398760
TicketExtensions.Describe(ticket): a ticket of 215000 paise
ticket.FareInRupees:               2150

Recorded with .NET SDK 10.0.401 (runtime 10.0.12) on macOS 26 arm64. To run it yourself: dotnet run wins.cs

ticket.Describe() printed the instance method’s ticket 4512398760; the extension ran only when called as a static method. The compiler binds every call while it compiles, and it looks at the type’s own members before any extension:

Interactive · stage by stage How the compiler binds a call on a Ticket Step through the two calls of wins.cs. The arrow aside is the search that stops at the type's own member.
How the compiler binds a call on a Ticket, step 6 of 6. Showing A call in Program.cs (ticket.FareInRupees), Ticket's own members (no FareInRupees), Extensions in scope (FareInRupees found), The call is bound (TicketExtensions call). In focus: The call is bound.a member fitsA call in Program.csticket.FareInRupeesTicket's own membersno FareInRupeesExtensions in scopeFareInRupees foundThe call is boundTicketExtensions call

The drawing shows the whole scene; its 6 steps are listed below.

Every step as text
  1. A call to bind. The compiler meets ticket.Describe() while it compiles Program.cs. It must choose one method for this call before the program ever runs.
  2. The type first. It searches the members of Ticket. Ticket declares Describe() with no parameters, which fits the call.
  3. The search ends. A member that fits ends the search, so the extension Describe() is never considered. The run printed ticket 4512398760.
  4. No member fits. For ticket.FareInRupees, Ticket has no member of that name, so the search goes on to the extensions that using directives bring into scope.
  5. An extension fits. TicketExtensions declares FareInRupees for a Ticket receiver. The call becomes a static call with the ticket as its argument, and it printed 2150.
  6. Fixed at compile time. Either way the choice is made once and kept in the compiled code. A member that a later version adds to Ticket changes the choice only when the app is compiled again.

The extension property could read FarePaise because it is public. An extension sees what any other code sees, so the private parts of Ticket stay out of reach, and it has no storage of its own: FareInRupees worked out its 2150 on every read. Three consequences follow. A library that later adds a member with an extension’s name takes over the call at the next build, without a warning. A struct receiver arrives as a copy unless the block takes it by ref. And two imported extensions with the same name make a call ambiguous, error CS0121.

Extensions are one design among several. A static helper method is the plain alternative: it takes the value as an ordinary argument. A new type, such as a checked bank code, can carry a rule that an extension on string never can.

Key idea

An extension is a static method that reads like a member: the compiler picks the type’s own member first, and an extension reaches only what other code may reach and stores nothing of its own.

Checkpoint

Check: Members first, no private members

  1. Question 1 of 2 Ticket declares Describe(), and an imported extension block declares Describe() for Ticket as well. Which runs for ticket.Describe()?

    Choose one answer.

    Show the answer: Question 1 of 2

    Answer: Ticket's own Describe()

    An extension can add to a type, never replace a member that it already has; the extension stays callable as a static method.

  2. Question 2 of 2 Which members of Ticket can an extension member use?

    Choose one answer.

    Show the answer: Question 2 of 2

    Answer: The ones any other code in that place could use, such as the public FarePaise

    An extension is code outside the type. If it needs more than the public surface, the type itself should gain the member.

When a library adds the member you extended: compile-time binding, reproduced Pro: opens with a Pro, Premium or Ultimate pass

An extension call is bound to a method when the caller is compiled, and a later version of the extended type can take the call away. The run below upgrades a library under an app, first without and then with a rebuild of the app.

In this part:

  • A Friday that becomes a weekend after a rebuild, reproduced
  • Guarding against a member that arrives later

3 runnable examples (C#, Python) · about 3 minutes

Opening this part with your pass…

This part opens with any MySmartCoPilot pass.

  • Pro pass · 1 week₹79$2.99
  • 30 days₹179$5.99
  • 1 year₹1,699$45

One payment; a pass never renews. The price shown is the total you pay: no fees or charges are added at checkout.

It also opens every other in-depth part in Learn and every Pro tool. Sales are final, except where the law gives you a right to withdraw, for example in the EU and the UK (refund policy).

Struct receivers and state an extension cannot hold, measured Pro: opens with a Pro, Premium or Ultimate pass

An extension’s receiver is a parameter, and for a struct a parameter is a copy. An extension also has no fields, so any value it remembers lives somewhere else. Both are measured below.

In this part:

  • A gate counter that stays at 0: by-value and ref receivers
  • No fields of their own: CS9282, CS0122, and 10,000 notes that never go away

3 runnable examples (C#, Python) · about 4 minutes

Opening this part with your pass…

This part opens with any MySmartCoPilot pass.

  • Pro pass · 1 week₹79$2.99
  • 30 days₹179$5.99
  • 1 year₹1,699$45

One payment; a pass never renews. The price shown is the total you pay: no fees or charges are added at checkout.

It also opens every other in-depth part in Learn and every Pro tool. Sales are final, except where the law gives you a right to withdraw, for example in the EU and the UK (refund policy).

Choosing between an extension, a helper and a new type, with the ambiguity a shared name causes Pro: opens with a Pro, Premium or Ultimate pass

Extensions are found by namespace, so two libraries that both extend a type can collide in your file. The run below reproduces the collision and its fix, and a table then helps decide when an extension is the right tool at all.

In this part:

  • CS0121: two imported extensions with the same name
  • A decision you can test against your own case

2 runnable examples (C#, Python) · about 7 minutes

Opening this part with your pass…

This part opens with any MySmartCoPilot pass.

  • Pro pass · 1 week₹79$2.99
  • 30 days₹179$5.99
  • 1 year₹1,699$45

One payment; a pass never renews. The price shown is the total you pay: no fees or charges are added at checkout.

It also opens every other in-depth part in Learn and every Pro tool. Sales are final, except where the law gives you a right to withdraw, for example in the EU and the UK (refund policy).

Practise: India’s tax year as DateOnly extensions

The tax year

The Income Tax Department describes the tax year of the Income-tax Act, 2025 as the twelve months of a financial year, from April to the following March, written as Tax Year 2026-27 for the first year of the new Act.

taxyear.cs checks three C# 14 extension members of DateOnly that you write: IsWeekend, TaxYear and the static DateOnly.Today(TimeProvider clock), the date in India at the clock’s time. They start out throwing, so all 9 checks fail:

taxyear.cs: nine checks of three extension members C# · practice/taxyear.cs
using System.Globalization;

// Practice: give DateOnly three C# 14 extension members. IsWeekend is true on Saturdays and Sundays. TaxYear names
// India's tax year, which runs from April to the following March, as "Tax Year 2026-27". DateOnly.Today(clock)
// returns the date in India, at UTC+05:30, at the clock's time. Run this file until all nine checks pass.
(string Check, Func<string> Run, string Expected)[] checks =
[
    ("a Saturday", () => new DateOnly(2026, 10, 17).IsWeekend.ToString(), "True"),
    ("a Monday", () => new DateOnly(2026, 10, 19).IsWeekend.ToString(), "False"),
    ("the first day of a tax year", () => new DateOnly(2026, 4, 1).TaxYear, "Tax Year 2026-27"),
    ("the last day of that year", () => new DateOnly(2027, 3, 31).TaxYear, "Tax Year 2026-27"),
    ("the day after", () => new DateOnly(2027, 4, 1).TaxYear, "Tax Year 2027-28"),
    ("a leap day", () => new DateOnly(2028, 2, 29).TaxYear, "Tax Year 2027-28"),
    ("a new century", () => new DateOnly(2099, 12, 1).TaxYear, "Tax Year 2099-00"),
    ("today from a clock", () => DateOnly.Today(Clock(2025, 11, 14, 6, 30)).ToString("yyyy-MM-dd", CultureInfo.InvariantCulture), "2025-11-14"),
    ("today in India, not in UTC", () => DateOnly.Today(Clock(2027, 3, 31, 20, 0)).TaxYear, "Tax Year 2027-28"),
];

int passed = 0;
foreach (var (check, run, expected) in checks)
{
    string got;
    try
    {
        got = run();
    }
    catch (Exception e)
    {
        got = $"throws {e.GetType().Name}";
    }

    bool ok = got == expected;
    if (ok)
    {
        passed++;
    }

    Console.WriteLine(ok ? $"{check}: ok" : $"{check}: FAIL, {got} instead of {expected}");
}

Console.WriteLine($"{passed} of {checks.Length} checks pass");
return passed == checks.Length ? 0 : 1;

// A clock that always gives this time in UTC.
static TimeProvider Clock(int year, int month, int day, int hour, int minute) =>
    new FixedClock(new DateTimeOffset(year, month, day, hour, minute, 0, TimeSpan.Zero));

sealed class FixedClock(DateTimeOffset utcNow) : TimeProvider
{
    public override DateTimeOffset GetUtcNow() => utcNow;
}

static class DateExtensions
{
    extension(DateOnly date)
    {
        public bool IsWeekend => throw new NotImplementedException();

        public string TaxYear => throw new NotImplementedException();
    }

    extension(DateOnly)
    {
        public static DateOnly Today(TimeProvider clock) => throw new NotImplementedException();
    }
}

Output (exit status 1)

a Saturday: FAIL, throws NotImplementedException instead of True
a Monday: FAIL, throws NotImplementedException instead of False
the first day of a tax year: FAIL, throws NotImplementedException instead of Tax Year 2026-27
the last day of that year: FAIL, throws NotImplementedException instead of Tax Year 2026-27
the day after: FAIL, throws NotImplementedException instead of Tax Year 2027-28
a leap day: FAIL, throws NotImplementedException instead of Tax Year 2027-28
a new century: FAIL, throws NotImplementedException instead of Tax Year 2099-00
today from a clock: FAIL, throws NotImplementedException instead of 2025-11-14
today in India, not in UTC: FAIL, throws NotImplementedException instead of Tax Year 2027-28
0 of 9 checks pass

Recorded with .NET SDK 10.0.401 (runtime 10.0.12) on macOS 26 arm64. To run it yourself: dotnet run taxyear.cs

Write the three members

Copy taxyear.cs. IsWeekend tests date.DayOfWeek. TaxYear starts at date.Year from April on and at date.Year - 1 before it, and writes the end year with two digits, (start + 1) % 100. Today converts clock.GetUtcNow() to the offset TimeSpan.FromHours(5.5) before DateOnly.FromDateTime. Run dotnet run taxyear.cs until it prints 9 of 9 checks pass.

Then check yourself:

Practice that adapts to you

Practise this lesson

9 questions about 6 ideas of this lesson. Each answer is explained at once, and what you get right is kept in this browser.

  1. Question 1 of 9 Which declaration is an extension method for string?

    Choose one answer.

    Show the answer: Question 1 of 9

    Answer: public static string Masked(this string text) in a static class that is neither nested nor generic

    The this modifier on the first parameter is what lets callers write pnr.Masked().

  2. Question 2 of 9 Another file of the same project calls pnr.Masked() but has no using Rail.Text; directive. What happens?

    Choose one answer.

    Show the answer: Question 2 of 9

    Answer: It does not compile: extension methods are in scope only where their namespace is imported

    Extensions are found by namespace: a file sees an extension only once it imports the namespace of the extension's static class.

  3. Question 3 of 9 In a project without implicit global usings, numbers.Where(n => n > 3) fails to compile on an int[] until using System.Linq; is added. Why?

    Choose one answer.

    Show the answer: Question 3 of 9

    Answer: Where is an extension method on IEnumerable<T>, declared in the System.Linq namespace

    LINQ is the largest use of extension methods: the operators live in static classes of System.Linq.

  4. Question 4 of 9 In extension(IEnumerable<int> counts) { … }, what is counts?

    Choose one answer.

    Show the answer: Question 4 of 9

    Answer: The receiver: the sequence that a member of the block is called on

    The receiver plays the role of the this parameter of a classic extension method.

  5. Question 5 of 9 You rewrite the classic method Busiest(this IEnumerable<int> counts) as a member of an extension block. What must its callers change?

    Choose one answer.

    Show the answer: Question 5 of 9

    Answer: Nothing: both forms compile to the same static method, so call sites stay the same

    Converting extension methods to blocks is a change inside the static class only.

  6. Question 6 of 9 Which member of blocks.cs could not have been written as a classic extension method at all?

    Choose one answer.

    Show the answer: Question 6 of 9

    Answer: IEnumerable<int>.Zeros(3), a static extension method

    Extension blocks add properties, static members and operators; the classic form adds instance methods only.

  7. Question 7 of 9 When does the compiler consider extension members for a call x.M()?

    Choose one answer.

    Show the answer: Question 7 of 9

    Answer: Only when the type of x has no member M that fits the call

    That rule is why ticket.Describe() reached Ticket's own method.

  8. Question 8 of 9 What does the extension property FareInRupees of wins.cs store?

    Choose one answer.

    Show the answer: Question 8 of 9

    Answer: Nothing: it works out FarePaise / 100m on every read

    Extensions add behaviour, not storage: every value they report is computed or read from somewhere else.

  9. Question 9 of 9 A teammate wants an extension to read a private field of a class that your team owns. What do you suggest?

    Choose one answer.

    Show the answer: Question 9 of 9

    Answer: Add the member to the class itself, since you own its source

    An extension reaches only what any other code may reach, so a member that needs a type's private fields belongs in the type, and you can add it there when the type is yours.

Day of the Week Calculator Check which day of the week a test date falls on before you write the expected value of IsWeekend.

Interview questions

Fresher · What is an extension method in C#?

A static method, declared in a static class that is not nested or generic, whose first parameter is marked this, such as public static string Masked(this string text). Once its namespace is imported, callers write pnr.Masked() as if string had the method, and the compiler turns the call into TextExtensions.Masked(pnr). It adds behaviour to a type without changing or deriving from it, which is how LINQ’s Where and Select reach every IEnumerable<T>. It cannot replace a member the type already has, and it never sees private members. C# 14 extension blocks add extension properties, static extension members and operators.

  1. Mid to senior

    Your app gives a library's Journey class an IsWeekend extension property. After a package upgrade and a rebuild, with no change to your code, Friday journeys start counting as weekends and every build still reports no warnings. What happened, and how do you fix it and guard against it?

    Model answer, Pro. Model answers open with any pass; prices are in the notice on this page. First step and follow-ups

  2. Mid to senior

    A teammate adds an extension property Customer.DisplayName and caches each result in a static Dictionary<Customer, string> to avoid recomputing it. In a long-running service, memory grows steadily. Review the design and propose a better one.

    Model answer, Pro. First step and follow-ups

  3. Fresher to mid

    Your payments code checks Indian bank branch codes (IFSC). Should the check be an extension property on string, such as code.IsIfsc, a static helper method, or a type Ifsc of its own? Choose one and defend it.

    Model answer, Pro. First step and follow-ups

Key takeaways

  • An extension method is a static method with this on its first parameter; the compiler turns x.M() into a static call, which is why a null receiver arrives as an argument.
  • C# 14 extension blocks declare instance members for a named receiver and static members and operators for a receiver type, and they compile to the same static methods as classic extensions.
  • The compiler picks the type’s own member before any extension, and an extension sees no private members and stores nothing of its own.

Terms in this lesson

extension block
A C# 14 declaration, extension(Type receiver) { … }, inside a static class. Its members become extension methods, extension properties and operators of that type; a block that names only the type, extension(Type), declares static extension members.
extension method
A static method of a static class whose first parameter is marked this, such as WordCount(this string text). Callers write text.WordCount(), and the compiler turns the call into TextExtensions.WordCount(text).
receiver
The value an extension member works on: the this parameter of an extension method, or the named parameter of an extension block, such as source in extension<T>(IEnumerable<T> source).

References

Related tools

Report a problem with this lesson

Quick answers and tool search

Type to search tools or to get a quick answer, for example 18% of 2500. Use the up and down arrow keys to move through the results, Enter to choose, and Escape to close.