CodeGym /Courses /C# SELF /Extension Members: Properties

Extension Members: Properties

C# SELF
Level 18, Lesson 3
Available

1. Introduction

Before, you could only add Extension methods to classes. But you couldn't add a property (property) as a class extension! So, if you wanted every DateTime to have an IsWeekend property, you had to do it through a method, which isn't always convenient — especially if you want the syntax date.IsWeekend instead of date.IsWeekend().

With the release of C# 14, the dream came true: now you can write extension properties in a way that's kinda similar to methods. They let you add a new property to an existing type without changing its original code, and use them just like regular properties!

Where is this actually useful?

  • For standard .NET types and third-party libraries where you can't change the code.
  • For handy "virtual" properties in view-models, UI, calculated views.
  • Whenever you want that nice syntax like .SomeCalculatedProperty without extra parentheses.

2. New Syntax in C# 14

In C# 14, they ditched the this keyword for extensions. Instead, there's a special operator extension(Type this). And with it, you can add new virtual stuff to a class.

Old Syntax

public static class StringExtensions
{
    public static bool IsNullOrWhiteSpace(this string str)
        => string.IsNullOrWhiteSpace(str);
}

New Syntax


public static class Enumerable
{
    extension(TSource source)
    {
        // Virtual members for the object
    }

    extension(TSource)
    {
        // Virtual static members
    }
}
New extension members syntax (C# 14+)

Important! This new extension syntax only works in C# 14+ and .NET 10+. If you're using .NET 9, it won't work. But if you wanna try it out and .NET 10 isn't out yet, just install .NET 10 preview 5+
Note! Our C# course uses the latest language features from C# 14+, even the ones that aren't officially released yet. In fall 2025, .NET 10 will drop, and by the time you finish the course, you'll have the most cutting-edge C# skills! 😎

3. Extension Properties Syntax

What does it look like?

Let's say you wanna add a property to DateTime that returns whether the date is a weekend:

public static class DateTimeExtensions
{
    public static bool IsWeekend(this DateTime date) => 
        date.DayOfWeek == DayOfWeek.Saturday || date.DayOfWeek == DayOfWeek.Sunday;
}

But that's the old Extension Method way, and you call it like: myDate.IsWeekend()

New Style — Extension Property


public static class DateTimeExtensions
{
    extension(DateTime source)
    {
        public bool IsWeekend // extension property!
        {
            get => source.DayOfWeek == DayOfWeek.Saturday || source.DayOfWeek == DayOfWeek.Sunday;
        }        
    }
}

Now you can write:

DateTime today = DateTime.Now;
if (today.IsWeekend)
{
    Console.WriteLine("You can sleep in!");
}

4. What Kinds of Extension Properties Are There?

You can add not only read-only properties, but also read-write ones:


public static class DateTimeExtensions
{
    extension(DateTime source)
    {
        public int YearFrom1900 // extension property!
        {
            get => source.Year - 1900;
            set => source.Year = value + 1900; 
        }        
    }
}
Read-write extension property
Important: For read-write extension properties, you gotta understand that they change the object itself, but can't store a "new" value somewhere else (like an auto field). If you wanna add a property that's not physically present in the object, you'll need a separate storage (like a dictionary), which is outside the scope of basic usage.

5. Static Properties

Thanks to the new syntax, you can add virtual properties not just to the object, but to the class itself! Yep, you heard right, now we can add virtual static properties to a class. The syntax is almost the same:


public static class DateTimeExtensions
{
    // New syntax: extension block for DateTime (C# 14)
    extension(DateTime)
    {
        // Static property to store the user's current time zone
        private static TimeZoneInfo _currentTimeZone = TimeZoneInfo.Local;

        // Extension property to access the current time zone
        public static TimeZoneInfo CurrentTimeZone
        {
            get => _currentTimeZone;
            set => _currentTimeZone = value ?? TimeZoneInfo.Local;
        }

        // Returns the time in the user's time zone
        public DateTime InCurrentTimeZone
        {
            get => TimeZoneInfo.ConvertTime(this, CurrentTimeZone);
        }
    }
}

6. Examples: Let's Extend the Dog Class!

Let's keep building our dog app, which we've been dragging along from lecture to lecture.

Now let's say we have not only dogs, but also a list of their vaccinations (List<DateTime>), but the Dog class is from a third-party library, and we can't change its code. We wanna add a property: Have all required vaccinations been done this year?

Old way (extension method):

public static class DogExtensions
{
    public static bool AllVaccinatedThisYear(this Dog dog)
    {
        return dog.Vaccinations.Any(v => v.Year == DateTime.Now.Year);
    }
}
// Usage:
if (myDog.AllVaccinatedThisYear())
    Console.WriteLine("Dog is healthy!");

New way (extension property):


public static class DogExtensions
{
    extension(Dog)
    {
        public bool AllVaccinatedThisYear
        {
            get => Vaccinations.Any(v => v.Year == DateTime.Now.Year);
        }
    }
}

// Usage:
if (myDog.AllVaccinatedThisYear)
    Console.WriteLine("Dog is healthy!");

Full Example

// Dog class — for example, from a third-party library:
public class Dog
{
    public string Name { get; set; }
    public List<DateTime> Vaccinations { get; set; } = new List<DateTime>();
}

// Extension class with extension block:
public static class DogExtensions
{
    extension(Dog)
    {
        public bool AllVaccinatedThisYear
        {
            get => Vaccinations.Any(v => v.Year == DateTime.Now.Year);
        }
    }
}

// In the program:
var myDog = new Dog { Name = "Buddy" };
myDog.Vaccinations.Add(new DateTime(DateTime.Now.Year, 2, 16)); // vaccination this year

Console.WriteLine($"{myDog.Name}: vaccinated? {(myDog.AllVaccinatedThisYear ? "Yes" : "No")}");

7. Table: Extension Methods vs Extension Properties

Extension Method Extension Property
Call Syntax obj.Method() obj.Property
Passes Parameters Yes No (only this obj)
Can Write Not applicable Only if implemented
Handy for View/UI Sometimes Yes (two-way bindings, lambda)
Visible in Reflection No No

8. Potential Pitfalls and Common Mistakes

When extension properties won't help

  • They can't fully replace real fields: they don't have access to private members of the object.
  • You can't add automatic state changes to the object (for example, you can't directly track value changes in the original class).
  • You can't use an extension property to implement an interface or abstract class.

Name collision

If the original class suddenly gets a property with the same name as yours, the "native" property will be used, not your extension. So be careful with naming, especially when working with public .NET types.

Problems with serialization/reflection

Extension property — it's not a "real" member of the type, just a handy syntactic sugar. So if you're using reflection or serialization somewhere, the extension property might not be visible to those tools.

2
Task
C# SELF, level 18, lesson 3
Locked
Creating an extension property to check for a leap year
Creating an extension property to check for a leap year
2
Task
C# SELF, level 18, lesson 3
Locked
Creating an extension property for a string
Creating an extension property for a string
Comments
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION