Extending C#: Myths and Truth About Extension Properties

Online Python Trainer for Beginners

Learn Python easily without overwhelming theory. Solve practical tasks with automatic checking, get hints in Russian, and write code directly in your browser — no installation required.

Start Course

Extension Properties in C#: When You Want To, But Can't (And How to Work Around It)



Imagine this situation: you're working with a library where the Person class has a FullName property. Everything is fine, but here's the catch — you need to add a computed property AgeInDays that calculates age in days from the date of birth. You're used to extension methods and think: "Why not make extension properties?"



And then you go to Stack Overflow, see a question with thousands of views: "Does C# have extension properties?" — and read the answer with disappointment: "No, they are not officially supported." But don't rush to close the tab! In this article, we'll not only figure out why they don't exist, but also find elegant workarounds that are no less performant.



Why Doesn't C# Add Extension Properties? Historical Context



Let's start with the main point: extension properties are not a whim, but a long-standing community request. Back in 2016, a proposal appeared on GitHub (C# feature request), but it still hasn't been implemented. Why?



  • Compiler complexity: Unlike methods, properties have getters and setters that must be tied to a specific instance. Extending this logic at the syntax level requires significant changes in the compiler.
  • Conflict with indexers: Properties and indexers in C# are closely related. Adding extension properties could create ambiguities.
  • Priority of other features: The C# team focused on records, pattern matching, and static abstract members (C# 11), which bring more benefits for most scenarios.


But the lack of official support is not a death sentence. Let's look at how experienced developers solve this problem.



Extension Methods: Your Main Tool (But With Nuances)



The most obvious way is to use extension methods instead of properties. Instead of person.AgeInDays, you write person.GetAgeInDays(). This works, but violates the principle of consistency: in the rest of the code, you use properties, but here suddenly a method.



public static class PersonExtensions{    public static int GetAgeInDays(this Person person)    {        return (DateTime.Now - person.BirthDate).Days;    }}

// Usage:var age = person.GetAgeInDays(); // Works, but not pretty


Downside: the code becomes less readable, especially in LINQ call chains. Upside: it's completely free in terms of performance — calling an extension method is no different from a regular static method.



Alternative #1: Static Factories and Helper Classes



If you need a "property" that is computed based on data, you can create a static helper class:



public static class PersonHelper{    public static int AgeInDays(Person person) => (DateTime.Now - person.BirthDate).Days;}

// Usage:var age = PersonHelper.AgeInDays(person);


This is more honest than an extension method: it's immediately clear that this is a helper function. But still not a property.



Alternative #2: Attributes and Code Generation (Source Generators)



For complex scenarios (e.g., adding properties to classes from NuGet packages), you can use source generators. They appeared in .NET 5 and allow you to generate code at compile time. You write an attribute, and the generator creates a partial class with the required properties.



[AutoExtensionProperty(typeof(Person), nameof(Person.BirthDate))]public partial class PersonExtensions{    // The generator will create the AgeInDays property}

// Generated code:public partial class PersonExt

Blogs

Book Recommendations