Problem
Is it true that C# has extension properties?
Can I, for example, add a ShortDateLongTimeFormat extension property to DateTimeFormatInfo that returns ShortDatePattern + ” ” + LongTimePattern?
Asked by Svish
Solution #1
The extension properties were not considered valuable enough to be included in prior editions of the C# standard until now. C# 7 and C# 8.0 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 from the start.
Extension members is included as a work item in the C# 7 work list, thus it may be supported soon. On Github, under the relevant item, you may get the current status of extension property.
However, there is a topic that is even more promising: “extend everything,” with a focus on properties, static classes, and even fields.
You can use the TypeDescriptor capability to attach an attribute to an object instance during runtime, as described in this article. It does not, however, use the usual property syntax. 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’m hoping that C#7 will include a full-featured extension that includes everything (properties and fields), but only time will tell.
Also, feel free to contribute, because tomorrow’s software will come from the community.
Update: August 2016
As a result of the dotnet team’s announcement of what’s new in C# 7.0, and based on a comment by Mads Torgensen:
Extension properties and other members appear to be good candidates for inclusion in a future Roslyn release, but perhaps not the 7.0 one.
Update: May 2017
The extension members problem was closed because it was a duplicate of the extension everything issue, which was also resolved. The main topic of discussion was Type extensibility in general. The feature is now tracked here as a proposal and has been removed from 7.0 milestone.
C# 8.0 suggested feature (as of August 2017)
While it is currently merely a suggested feature, we now have a better idea of how it would work. Remember that this will also be the new syntax for extension methods:
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;
Partial classes are similar, except they are compiled as a separate class/type in a different assembly. It’s worth noting that you’ll be able to add static members and operators this way as well. As discussed in Mads Torgensen’s podcast, the extension will be stateless (i.e., it won’t be able to add private instance members to the class), therefore you won’t be able to add private instance data to the instance. The explanation given is that it would necessitate managing internal dictionaries, which may be challenging (memory management, etc…). For this, you may still utilize the TypeDescriptor/ConditionalWeakTable approach, which conceals it beneath a lovely property with the property extension.
As this problem implies, syntax is still subject to change. Extends, for example, may be replaced by, which may feel more natural and less java-related to some.
Roles, Extensions, and static interface members were updated in December 2018.
Because of some of the problems detailed at the end of this GitHub ticket, the extension did not make it to C# 8.0. As a result, an attempt was made to improve the design. Mads Torgensen discusses what roles and extensions are and how they differ in this video:
It can be observed in a previous proposal that was separated into two use cases. The new extension syntax would be as follows:
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’d be able to accomplish the following:
foreach (byte b in 0x_3A_9E_F1_C5_DA_F7_30_16ul)
{
WriteLine($"{e.Current:X}");
}
And here’s how you make 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 to int and make it IMonoidint>:
public extension IntMonoid of int : IMonoid<int>
{
public static int Zero => 0;
}
Answered by Fab
Solution #2
No, they aren’t in C# 3.0 and won’t be added in 4.0. It’s on the list of C# feature requests, so it could be introduced in the future.
The most you can do at this point is use GetXXX style extension methods.
Answered by JaredPar
Solution #3
They don’t exist, no.
I know the C# team (or at least Eric Lippert) considered these at one point, along with extension constructors and operators (those may take a while to get your head around, but are cool…) However, I’ve seen no indication that they’ll be included in C# 4.
EDIT: They weren’t in C# 5, and it doesn’t look like they’ll be in C# 6 either, as of July 2014.
Eric Lippert, a Principal Developer on Microsoft’s C# compiler team from October 2009 to November 2012, blogged about it:
Answered by Jon Skeet
Solution #4
(Thanks to @chaost for bringing this to my attention):
Source: https://blogs.msdn.microsoft.com/dotnet/2018/11/12/building-c-8-0/ comments section
I’ve lost track of how many times I’ve asked this question over the years in the hopes of seeing it implemented.
Finally, we can all be happy! Microsoft is going to introduce this in their upcoming C# 8 release.
So instead of doing that, I’m going to…
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/
Answered by Korayem
Solution #5
You may use the conditionalWeakTable to add properties to existing objects, like @Psyonity mentioned. You may build dynamic extension attributes in a few lines using the dynamic ExpandoObject:
using System.Dynamic;
using System.Runtime.CompilerServices;
namespace ExtensionProperties
{
/// <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 < 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 ConditionalWeakTable<object, object>();
/// <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());
}
}
In the xml comments, there is an example of how to use it:
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
Answered by realbart
Post is based on https://stackoverflow.com/questions/619033/does-c-sharp-have-extension-properties