969

Does C# have extension properties?

For example, can I add an extension property to DateTimeFormatInfo called ShortDateLongTimeFormat which would return ShortDatePattern + " " + LongTimePattern?

6
  • 21
    I wanted to add an extension method called IsNull on Nullable<T> which would just return ! HasValue. .IsNull() is definately less pretty than .IsNull Commented Aug 3, 2011 at 19:02
  • 1
    I find this useful for trinary operator ? Commented Aug 24, 2012 at 17:59
  • 2
    I wanted this to mimic Java's enums which can have properties and methods. C#'s enums can't have properties or methods, but you can create extension methods on them. This question was useful to me, and shouldn't be closed. Commented Sep 25, 2014 at 13:51
  • Although, as many people have said, there are no plans currently in place to add this to the language, there's no reason it couldn't be done. The fact that F# has not only extension properties but static extensions as well to me proves that it is at least a good idea. Commented Oct 21, 2014 at 9:36
  • 3
    There should be made one Commented Aug 6, 2016 at 8:21

10 Answers 10

718

For the moment it is still not supported out of the box by Roslyn compiler ...

Until now, the extension properties were not seen as valuable enough to be included in the previous versions of C# standard. Various C# versions (maybe all of them?) have seen this as proposal champion but it wasn't released yet, most of all because even if there is already an implementation, they want to make it right.

But it will maybe... one day ...

Update 2025:

Finally it's planned for C#14

Update 2022:

The features seems to be still in discussion here.

Moreover you can use a workaround

As specified in this article, you can use the TypeDescriptor capability to attach an attribute to an object instance at runtime. However, it is not using the syntax of the standard properties.
It's a little bit different from just syntactic sugar adding a possibility to define an extended property like
string Data(this MyClass instance) as an alias for extension method
string GetData(this MyClass instance) as it stores data into the class.

I hope that C# will soon provide a full featured extension everything (properties and fields), however on that point, only time will tell.

And feel free to contribute as the software of tomorrow will come from the community.

Post processing approach

If you are allowed to do so, you could also add dynamically a property on a class in your assembly after compilation with tools like PostSharp, Mono.Cecil (or similar code/IL rewrite tool).

However, as a developer explained in the above discussion, rewriting code won't let the compiler knows your intent and thus it will probably fail at optimizing your resulting code. As a language feature, the result is expected to be better.

A bit of history

There was an extension members item in the C# 7 work list so I thought it might be supported in the near future. The current status of extension property can be found on Github under the related item.

However, there is an even more promising topic which is the "extend everything" with a focus on especially properties and static classes or even fields.

Update: August 2016

As dotnet team published what's new in C# 7.0 and from a comment of Mads Torgensen:

Extension properties: we had a (brilliant!) intern implement them over the summer as an experiment, along with other kinds of extension members. We remain interested in this, but it’s a big change and we need to feel confident that it’s worth it.

It seems that extension properties and other members, are still good candidates to be included in a future release of Roslyn, but maybe not the 7.0 one.

Update: May 2017

The extension members has been closed as duplicate of extension everything issue which is closed too. The main discussion was in fact about Type extensibility in a broad sense. The feature is now tracked here as a proposal and has been removed from 7.0 milestone.

Update: August, 2017 - C# 8.0 proposed feature

While it still remains only a proposed feature, we have now a clearer view of what would be its syntax. Keep in mind that this will be the new syntax for extension methods as well:

public interface IEmployee { public decimal Salary { get; set; } } public class Employee { public decimal Salary { get; set; } } public extension MyPersonExtension extends Person : IEmployee { private static readonly ConditionalWeakTable<Person, Employee> _employees = new ConditionalWeakTable<Person, Employee>(); public decimal Salary { get { // `this` is the instance of Person return _employees.GetOrCreate(this).Salary; } set { Employee employee = null; if (!_employees.TryGetValue(this, out employee) { employee = _employees.GetOrCreate(this); } employee.Salary = value; } } } IEmployee person = new Person(); var salary = person.Salary; 

Similar to partial classes, but compiled as a separate class/type in a different assembly. Note you will also be able to add static members and operators this way. As mentioned in Mads Torgensen podcast, the extension won't have any state (so it cannot add private instance members to the class) which means you won't be able to add private instance data linked to the instance. The reason invoked for that is it would imply to manage internally dictionaries and it could be difficult (memory management, etc...). For this, you can still use the TypeDescriptor/ConditionalWeakTable technique described earlier and with the property extension, hides it under a nice property.

Syntax is still subject to change as implies this issue. For example, extends could be replaced by for which some may feel more natural and less java related.

Update December 2018 - Roles, Extensions and static interface members

Extension everything didn't make it to C# 8.0, because of some of drawbacks explained as the end of this GitHub ticket. So, there was an exploration to improve the design. Here, Mads Torgensen explains what are roles and extensions and how they differs:

Roles allow interfaces to be implemented on specific values of a given type. Extensions allow interfaces to be implemented on all values of a given type, within a specific region of code.

It can be seen at a split of previous proposal in two use cases. The new syntax for extension would be like this:

public extension ULongEnumerable of ulong { public IEnumerator<byte> GetEnumerator() { for (int i = sizeof(ulong); i > 0; i--) { yield return unchecked((byte)(this >> (i-1)*8)); } } } 

then you would be able to do this:

foreach (byte b in 0x_3A_9E_F1_C5_DA_F7_30_16ul) { WriteLine($"{e.Current:X}"); } 

And for a static interface:

public interface IMonoid<T> where T : IMonoid<T> { static T operator +(T t1, T t2); static T Zero { get; } } 

Add an extension property on int and treat the int as IMonoid<int>:

public extension IntMonoid of int : IMonoid<int> { public static int Zero => 0; } 
Sign up to request clarification or add additional context in comments.

6 Comments

This is one of the most useful answers I've ever followed on StackExchange. Constantly updating with the status and keeping everyone informed that comes back to this, providing solid links to discussion and history.
It's terrific that you are keeping this up to date - thank you
Unfortunately as of this comment, roles, extensions and static interface members are only flagged for C# 11 :(
It appears the "extension everything" proposal has been closed, and the continuation appears to be in this ticket: github.com/dotnet/csharplang/issues/192
any update for 2022?
|
448

No they do not exist in C# 3.0 and will not be added in 4.0. It's on the list of feature wants for C# so it may be added at a future date.

At this point the best you can do is GetXXX() style extension methods.

4 Comments

Similarly with generic properties: you have to use 'GetXXX<>' syntax.
ok, that's what I thought. @Jay, yeah, I hate that too, hehe. Especially the inability to have a generic indexer... sigh
Link to list of feature wants?
What about Version 6.0 and 7.0?
276

No, they don't exist.

I know that the C# team was considering them at one point (or at least Eric Lippert was) - along with extension constructors and operators (those may take a while to get your head around, but are cool...) However, I haven't seen any evidence that they'll be part of C# 4.


EDIT: They didn't appear in C# 5, and as of July 2014 it doesn't look like it's going to be in C# 6 either.

Eric Lippert, the Principal Developer on the C# compiler team at Microsoft thru November 2012, blogged about this in October of 2009:

13 Comments

Yes, and they could still hide the field - setting a single property might set two properties underneath, or vice versa. (Imagine something with a normal Size property, and Width/Height extension properties, or vice versa.) They'd be more useful as read-only ones though, I suspect.
You can't bind to extension methods... being able to add your own properties for databinding could be helpful in many situations.
@leppie - The value of property extensions would benefit bool and string properties the most I think. Getting rid of the () at the end is much more readable. I know for me personally, at least 90% of the extensions I write are of those 2 types.
To give an example of why this would be useful, I have an EFCF model. In some of the classes I have read-only properties that I use to return formatted information: FullName = FirstName + LastName, ShortName = FirstName + LastName[0]. I would like to add more of these properties, but I don't want to "dirty" the actual classes. In this case an extension property, that's read-only, is perfect because I can add the functionality, keep the main class clean, and still expose the information I want to expose in the UI.
@JonSkeet : You're right, I ended up doing what I wanted by creating my own class, then wrapping all the relevant sealed class methods and properties, then providing static implicit operator FileInfo(FileInfoEx fex) which returns my contained FileInfo object. This effectively lets me treat the FileInfoEx as if it inherits from FileInfo, even though that class is sealed.
|
29

Update (thanks to @chaost for pointing this update out):

Mads Torgersen: "Extension everything didn’t make it into C# 8.0. It got “caught up”, if you will, in a very exciting debate about the further future of the language, and now we want to make sure we don’t add it in a way that inhibits those future possibilities. Sometimes language design is a very long game!"

Source: comments section in https://blogs.msdn.microsoft.com/dotnet/2018/11/12/building-c-8-0/


I stopped counting how many times over the years I opened this question with hopes to have seen this implemented.

Well, finally we can all rejoice! Microsoft is going to introduce this in their upcoming C# 8 release.

So instead of doing this...

public static class IntExtensions {    public static bool Even(this int value)    {         return value % 2 == 0;    } } 

We'll be finally able to do it like so...

public extension IntExtension extends int { public bool Even => this % 2 == 0; } 

Source: https://blog.ndepend.com/c-8-0-features-glimpse-future/

2 Comments

This week C# 8.0 features were announced and I didn't see any of this unfortunately.
@MateoTorres-Ruiz A comment from 'Mads Torgersen' (C# dev), replying to someone asking about it (3 days ago): "Extension everything didn’t make it into C# 8.0. It got “caught up”, if you will, in a very exciting debate about the further future of the language, and now we want to make sure we don’t add it in a way that inhibits those future possibilities. Sometimes language design is a very long game!" Feels bad.. (Read this on Korayems link, in the comment section)
12

The term "Extension Properties" Can be interpreted in two ways:

  • Having in essence a set of two methods, a getter and a setter, which can be called just as you would access a property. The feature will be called "Extension Members" and will probably be in .net 10 / C#14.

  • Storing extra data for instances of specific types. This can be achieved using a ConditionalWeakTable.

Extension members

The new way to define any extension (including extension methods) is using the extension keyword. This can be even be used to create static extensions.

Note: for now, you need to enable the language preview in you project file.

<PropertyGroup> <OutputType>Exe</OutputType> <TargetFramework>net10.0</TargetFramework> <LangVersion>preview</LangVersion> </PropertyGroup> 

This way, you can:

public class BalancedTernary { // Contains a special type of number. // Let's say it has a constructor accepting a string // and a property Int32Value that shows the integer value. } public static class Extensions { // extension property on string instances. // string s = "T10T10".TernaryValue extension(string target) { BalancedTernary TernaryValue => new(source); } // static extension on int // int i = int.Parse(new BalancedTernary("T10T10")) extension(int) { static int Parse(BalancedTernary source) => source.Int32Value; } } 

ConditionalWeakTable

As @Psyonity mentioned, you can use the conditionalWeakTable to add properties to existing objects. Combined with the dynamic ExpandoObject, you could implement dynamic extension properties in a few lines:

namespace ExtensionProperties; using System.Dynamic; using System.Runtime.CompilerServices; /// <summary> /// Dynamically associates properies to a random object instance /// </summary> /// <example> /// var jan = new Person("Jan"); /// /// jan.Age = 24; // regular property of the person object; /// jan.DynamicProperties().NumberOfDrinkingBuddies = 27; // not originally scoped to the person object; /// /// if (jan.Age &lt; jan.DynamicProperties().NumberOfDrinkingBuddies) /// Console.WriteLine("Jan drinks too much"); /// </example> /// <remarks> /// If you get 'Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo.Create' you should reference Microsoft.CSharp /// </remarks> public static class ObjectExtensions { ///<summary>Stores extended data for objects</summary> private static ConditionalWeakTable<object, object> extendedData = new(); /// <summary> /// Gets a dynamic collection of properties associated with an object instance, /// with a lifetime scoped to the lifetime of the object /// </summary> /// <param name="obj">The object the properties are associated with</param> /// <returns>A dynamic collection of properties associated with an object instance.</returns> public static dynamic DynamicProperties(this object obj) => extendedData.GetValue(obj, _ => new ExpandoObject()); } 

A usage example is in the xml comments:

var jan = new Person("Jan"); jan.Age = 24; // regular property of the person object; jan.DynamicProperties().NumberOfDrinkingBuddies = 27; // not originally scoped to the person object; if (jan.Age < jan.DynamicProperties().NumberOfDrinkingBuddies) { Console.WriteLine("Jan drinks too much"); } jan = null; // NumberOfDrinkingBuddies will also be erased during garbage collection 

Combination

This might look something like this:

namespace ExtensionProperties;

using System.Runtime.CompilerServices; public class Language(string name) { public static Language Default = new Language("en"); public static Language French = new Language("fr"); public override string ToString() => name; } public static class Extensions { private static ConditionalWeakTable<string, Language> languages = new(); extension(string source) { public Language Language { get => languages.GetValue(source, _ => Language.Default); set => languages.AddOrUpdate(source, value); } } } 

so we could:

string s = "bonjour"; s.Language = Language.French; 

NOTE: String Interning may lead to surprising behavior when used with a ConditionalWeakTable. This is just an example.

3 Comments

The best answer
@N73k No, not the best answer at all. Do you have the slightest clue as to what the performance overhead of dynamic properties is? We use languages like C# because they are strongly typed and because they compile to native code, for performance. dynamic properties invalidate all of that.
The question is whether it is possible, not whether you should :-) However, I'm convinced there's valid use cases for the ConditionalWeakTable, despite its performance implications.
6

This should exist in C# 13, source:

Example usage (for your scenario):

public implicit extension DateTimeFormatInfoExtension for DateTimeFormatInfo { public string ShortDateLongTimeFormat => this.ShortDatePattern + " " + this.LongTimePattern; } 

The implicit here means it applies to all DateTimeFormatInfo (as long as the extension type is in scope via the using directives, the same as extension methods); if it was explicit, you'd need to assign a DateTimeFormatInfo to a DateTimeFormatInfoExtension value.

4 Comments

Is it possible to test out code like this ? I have looked at the Sharplab.io site, but the code in your answer was not possible to compile with any of the versions of compiler there, but maybe I chose the wrong versions.
@ToreAurstad if it doesn't list the branch on sharplab, then another option is to find the branch in the dotnet/roslyn repo and build it manually; I can't find such a branch, though - it is possible that it only exists in slides at this point. I want to say that this is the "Working Set: Roles/Extensions" piece in sharplab, but I can't get it to work currently
For anyone interested: This feature had been presented at the MsBuild. youtube.com/watch?v=O3hx6oPWzX8&t=1175s
Another addition: The extension properties are part of the extension types feature, which Microsoft won't get fully done with C# 13. According to the latest news, some parts of that feature will be delivered with C# 14. Source: devblogs.microsoft.com/dotnet/…
2

Because I recently needed this, I looked at the source of the answer in:

c# extend class by adding properties

and created a more dynamic version:

public static class ObjectExtenders { static readonly ConditionalWeakTable<object, List<stringObject>> Flags = new ConditionalWeakTable<object, List<stringObject>>(); public static string GetFlags(this object objectItem, string key) { return Flags.GetOrCreateValue(objectItem).Single(x => x.Key == key).Value; } public static void SetFlags(this object objectItem, string key, string value) { if (Flags.GetOrCreateValue(objectItem).Any(x => x.Key == key)) { Flags.GetOrCreateValue(objectItem).Single(x => x.Key == key).Value = value; } else { Flags.GetOrCreateValue(objectItem).Add(new stringObject() { Key = key, Value = value }); } } class stringObject { public string Key; public string Value; } } 

It can probably be improved a lot (naming, dynamic instead of string), I currently use this in CF 3.5 together with a hacky ConditionalWeakTable (https://gist.github.com/Jan-WillemdeBruyn/db79dd6fdef7b9845e217958db98c4d4)

1 Comment

Sorry, but although this looks very thorough, it has nothing to do with extension properties, but only shows extension methods.
2

Great news from November 2025. It's officially released.

https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/extension-methods

Here is short example.

public class DomainEntity { public required string FirstName { get; set; } public required string LastName { get; set; } } static class DomainEntityExtensions { extension(DomainEntity value) { string FullName => $"{value.FirstName} {value.LastName}"; } } 

Comments

1

The feature almost made it to C#13. Moved probably to C#14:

https://devblogs.microsoft.com/dotnet/csharp-13-explore-preview-features/#update-on-extension-types

public implicit extension PersonExtension for Person { public bool IsLead => this.Organization .Teams .Any(team => team.Lead == this); } 

This property would be called as:

if (person.IsLead) { ... } 

Comments

0

Extension properties can be made in C#14. This is available with .NET 10.

It is not possible to define a generic extension block to add extension properties / members (yet, as of C#14 anyways -maybe for future version of C#..)

Consider this example of some well-known constants from entry-level Calculus using extension properties.

using System.Numerics; namespace Csharp14NewFeatures { /// <summary> /// Provides well-known mathematical constants for any numeric type using generic math. /// </summary> /// <typeparam name="T">A numeric type implementing INumber&lt;T&gt; (e.g., double, decimal, float).</typeparam> public static class MathConstants<T> where T : INumber<T> { /// <summary>π (Pi), ratio of a circle's circumference to its diameter.</summary> public static T Pi => T.CreateChecked(Math.PI); /// <summary>τ (Tau), equal to 2π. Represents one full turn in radians.</summary> public static T Tau => T.CreateChecked(2 * Math.PI); /// <summary>e (Euler's number), base of the natural logarithm.</summary> public static T E => T.CreateChecked(Math.E); /// <summary>φ (Phi), the golden ratio (1 + √5) / 2.</summary> public static T Phi => T.CreateChecked((1 + Math.Sqrt(5)) / 2); /// <summary>√2, square root of 2. Appears in geometry and trigonometry.</summary> public static T Sqrt2 => T.CreateChecked(Math.Sqrt(2)); /// <summary>√3, square root of 3. Common in triangle geometry.</summary> public static T Sqrt3 => T.CreateChecked(Math.Sqrt(3)); /// <summary>ln(2), natural logarithm of 2.</summary> public static T Ln2 => T.CreateChecked(Math.Log(2)); /// <summary>ln(10), natural logarithm of 10.</summary> public static T Ln10 => T.CreateChecked(Math.Log(10)); /// <summary>Degrees-to-radians conversion factor (π / 180).</summary> public static T Deg2Rad => T.CreateChecked(Math.PI / 180.0); /// <summary>Radians-to-degrees conversion factor (180 / π).</summary> public static T Rad2Deg => T.CreateChecked(180.0 / Math.PI); } /// <summary> /// Extension blocks exposing math constants as properties for common numeric types. /// </summary> public static class MathExtensions { extension(double source) { /// <inheritdoc cref="MathConstants{T}.Pi"/> public double Pi => MathConstants<double>.Pi; /// <inheritdoc cref="MathConstants{T}.Tau"/> public double Tau => MathConstants<double>.Tau; /// <inheritdoc cref="MathConstants{T}.E"/> public double E => MathConstants<double>.E; /// <inheritdoc cref="MathConstants{T}.Phi"/> public double Phi => MathConstants<double>.Phi; /// <inheritdoc cref="MathConstants{T}.Sqrt2"/> public double Sqrt2 => MathConstants<double>.Sqrt2; /// <inheritdoc cref="MathConstants{T}.Sqrt3"/> public double Sqrt3 => MathConstants<double>.Sqrt3; /// <inheritdoc cref="MathConstants{T}.Ln2"/> public double Ln2 => MathConstants<double>.Ln2; /// <inheritdoc cref="MathConstants{T}.Ln10"/> public double Ln10 => MathConstants<double>.Ln10; /// <inheritdoc cref="MathConstants{T}.Deg2Rad"/> public double Deg2Rad => MathConstants<double>.Deg2Rad; /// <inheritdoc cref="MathConstants{T}.Rad2Deg"/> public double Rad2Deg => MathConstants<double>.Rad2Deg; } extension(decimal source) { public decimal Pi => MathConstants<decimal>.Pi; public decimal Tau => MathConstants<decimal>.Tau; public decimal E => MathConstants<decimal>.E; public decimal Phi => MathConstants<decimal>.Phi; public decimal Sqrt2 => MathConstants<decimal>.Sqrt2; public decimal Sqrt3 => MathConstants<decimal>.Sqrt3; public decimal Ln2 => MathConstants<decimal>.Ln2; public decimal Ln10 => MathConstants<decimal>.Ln10; public decimal Deg2Rad => MathConstants<decimal>.Deg2Rad; public decimal Rad2Deg => MathConstants<decimal>.Rad2Deg; } extension(float source) { public float Pi => MathConstants<float>.Pi; public float Tau => MathConstants<float>.Tau; public float E => MathConstants<float>.E; public float Phi => MathConstants<float>.Phi; public float Sqrt2 => MathConstants<float>.Sqrt2; public float Sqrt3 => MathConstants<float>.Sqrt3; public float Ln2 => MathConstants<float>.Ln2; public float Ln10 => MathConstants<float>.Ln10; public float Deg2Rad => MathConstants<float>.Deg2Rad; public float Rad2Deg => MathConstants<float>.Rad2Deg; } } } 

We must define extension blocks per type here.

If we move over to extension methods, we still must use a non-generic class. However, we can use for example generic math, show below. This allows to reuse code accross multiple types, supporting INumber in this case.

namespace Csharp14NewFeatures { using System; using System.Numerics; namespace Csharp14NewFeatures { /// <summary> /// Provides generic mathematical constants via extension methods for numeric types. /// </summary> public static class MathConstantExtensions { /// <summary>Returns π (Pi), the ratio of a circle's circumference to its diameter.</summary> public static T GetPi<T>(this T _) where T : INumber<T> => T.CreateChecked(Math.PI); /// <summary>Returns τ (Tau), equal to 2π. Represents one full turn in radians.</summary> public static T GetTau<T>(this T _) where T : INumber<T> => T.CreateChecked(2 * Math.PI); /// <summary>Returns e (Euler's number), the base of the natural logarithm.</summary> public static T GetEuler<T>(this T _) where T : INumber<T> => T.CreateChecked(Math.E); /// <summary>Returns φ (Phi), the golden ratio (1 + √5) / 2.</summary> public static T GetPhi<T>(this T _) where T : INumber<T> => T.CreateChecked((1 + Math.Sqrt(5)) / 2); /// <summary>Returns √2, the square root of 2.</summary> public static T GetSqrt2<T>(this T _) where T : INumber<T> => T.CreateChecked(Math.Sqrt(2)); /// <summary>Returns √3, the square root of 3.</summary> public static T GetSqrt3<T>(this T _) where T : INumber<T> => T.CreateChecked(Math.Sqrt(3)); /// <summary>Returns ln(2), the natural logarithm of 2.</summary> public static T GetLn2<T>(this T _) where T : INumber<T> => T.CreateChecked(Math.Log(2)); /// <summary>Returns ln(10), the natural logarithm of 10.</summary> public static T GetLn10<T>(this T _) where T : INumber<T> => T.CreateChecked(Math.Log(10)); /// <summary>Returns the degrees-to-radians conversion factor (π / 180).</summary> public static T GetDeg2Rad<T>(this T _) where T : INumber<T> => T.CreateChecked(Math.PI / 180.0); /// <summary>Returns the radians-to-degrees conversion factor (180 / π).</summary> public static T GetRad2Deg<T>(this T _) where T : INumber<T> => T.CreateChecked(180.0 / Math.PI); } } } 

Example usage of the code above :

 #region Extension metmbers using block syntax - Math //Extension properties double radians = double.Pi / 3.0; // Pi/3 radians = 60 degrees (1 * Pi = 180 degrees) double degrees = radians * radians.Rad2Deg; // Using the extension method Rad2Deg Console.WriteLine($"Radians: {radians:F6}"); //outputs 1.04719.. Console.WriteLine($"Degrees: {degrees:F6}"); //outputs 60 //Using Extension methods double radiansV2 = 1.0.GetPi() / 3.0; double degreesV2 = radians * 1.0.GetRad2Deg(); Console.WriteLine($"Radians: {radiansV2:F6}"); Console.WriteLine($"Degrees: {degreesV2:F6}"); 

Output

Radians: 1,047198 Degrees: 60,000000 Radians: 1,047198 Degrees: 60,000000

It perhaps feels more 'natural' to constants such as Euler's number and Pi and many other constants of math (and physics and more!) as extension members - that is properties. In this case, note that we got Math.PI and Math.E already defined as double fields of Math. But the example code above should show how you could build up a 'catalog' of well-known mathematical constants and conversion factors of Calculus.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.