C#有扩展属性吗?
例如,我可以添加一个扩展属性来DateTimeFormatInfo
调用ShortDateLongTimeFormat
哪个会返回ShortDatePattern + " " + LongTimePattern
?
不,它们不存在于C#3.0中,也不会在4.0中添加.它位于C#的功能需求列表中,因此可能会在将来添加.
此时,您可以做的最好的是GetXXX样式扩展方法.
不,他们不存在.
我知道C#团队正在考虑他们(或者至少是Eric Lippert) - 以及扩展构造者和操作员(这些可能需要一段时间才能让你的头脑清醒,但很酷......)但是,我没有没有看到任何证据表明他们将成为C#4的一部分.
编辑:他们没有出现在C#5中,截至2014年7月,它看起来也不会出现在C#6中.
微软C#编译团队首席开发人员Eric Lippert于2012年11月在博客中发表了关于此问题的文章:
为什么没有扩展属性? - 编码中的神话般的冒险
到目前为止,扩展属性被认为不足以包含在以前版本的C#标准中.C#7和C#8.0已将此视为提案冠军,但尚未发布,最重要的是因为即使已经有实施,他们也希望从一开始就做到正确.
C#7工作列表中有一个扩展成员项,因此可能在不久的将来支持它.扩展属性的当前状态可以在相关项下的Github上找到.
然而,有一个更有希望的主题是"扩展一切",重点是特别是属性和静态类甚至字段.
如本文所述,您可以使用该TypeDescriptor
功能在运行时将属性附加到对象实例.但是,它没有使用标准属性的语法.
它与语法糖略有不同,增加了定义扩展属性的可能性,例如string Data(this MyClass instance)
作为扩展方法的别名,string GetData(this MyClass instance)
因为它将数据存储到类中.
我希望C#7能提供全功能的扩展(属性和字段),但是在这一点上,只有时间会证明.
并随意贡献,因为明天的软件将来自社区.
更新:2016年8月
随着dotnet团队发布了C#7.0中的新内容以及Mads Torgensen的评论:
扩展属性:我们有一个(辉煌!)实习生在夏天实施它们作为实验,以及其他类型的扩展成员.我们仍然对此感兴趣,但这是一个很大的变化,我们需要确信这是值得的.
似乎扩展属性和其他成员仍然是未来发布的Roslyn中的好选择,但可能不是7.0.
更新:2017年5月
扩展成员已被关闭作为扩展的所有问题的副本也被关闭.主要的讨论实际上是广义上的类型可扩展性.此功能现在作为提案进行跟踪,已从 7.0里程碑中删除.
更新:2017年8月 - C#8.0提议的功能
虽然它仍然只是一个提议的功能,但我们现在可以更清楚地了解它的语法.请记住,这也是扩展方法的新语法:
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_employees = new ConditionalWeakTable (); 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;
与部分类类似,但在不同的程序集中编译为单独的类/类型.请注意,您也可以通过这种方式添加静态成员和运算符.如Mads Torgensen播客中所述,扩展将不具有任何状态(因此它无法将私有实例成员添加到类中),这意味着您将无法添加链接到该实例的私有实例数据.为此调用的原因是它意味着管理内部词典并且可能很难(内存管理等).为此,您仍然可以使用前面描述的TypeDescriptor
/ ConditionalWeakTable
技术和属性扩展,将其隐藏在一个不错的属性下.
语法仍然会发生变化,因为这意味着这个问题.例如,extends
可以替换为for
某些可能感觉更自然且与Java相关的更少.
更新2018年12月 - 角色,扩展和静态接口成员
扩展一切都没有进入C#8.0,因为一些缺点被解释为这个GitHub票的结束.因此,有一项改进设计的探索.在这里,Mads Torgensen解释了什么是角色和扩展以及它们的区别:
角色允许在给定类型的特定值上实现接口.扩展允许在特定代码区域内的给定类型的所有值上实现接口.
在两个用例中,可以看出先前提案的拆分.扩展的新语法如下:
public extension ULongEnumerable of ulong { public IEnumeratorGetEnumerator() { for (int i = sizeof(ulong); i > 0; i--) { yield return unchecked((byte)(this >> (i-1)*8)); } } }
然后你就可以这样做:
foreach (byte b in 0x_3A_9E_F1_C5_DA_F7_30_16ul) { WriteLine($"{e.Current:X}"); }
对于静态接口:
public interface IMonoidwhere T : IMonoid { static T operator +(T t1, T t2); static T Zero { get; } }
添加扩展属性上int
和治疗int
为IMonoid
:
public extension IntMonoid of int : IMonoid{ public static int Zero => 0; }
更新(感谢@chaost指出此更新):
Mads Torgersen: "扩展所有内容都没有进入C#8.0.如果你愿意的话,它会被"赶上",在一场关于该语言未来发展的激动人心的辩论中,现在我们要确保我们不要以一种抑制未来可能性的方式添加它.有时语言设计是一个非常漫长的游戏!"
来源:https : //blogs.msdn.microsoft.com/dotnet/2018/11/12/building-c-8-0/中的评论部分
多年来我一直打开这个问题,希望能够看到这个问题,我已经停止计算了多少次.
好吧,最后我们都欢喜!微软将在他们即将发布的C#8版本中介绍这一点.
所以不要这样做......
public static class IntExtensions { public static bool Even(this int value) { return value % 2 == 0; } }
我们终于能够这样做......
public extension IntExtension extends int { public bool Even => this % 2 == 0; }
资料来源:https://blog.ndepend.com/c-8-0-features-glimpse-future/
正如@Psyonity所提到的,您可以使用conditionalWeakTable向现有对象添加属性.结合动态ExpandoObject,您可以在几行中实现动态扩展属性:
using System.Dynamic; using System.Runtime.CompilerServices; namespace ExtensionProperties { ////// Dynamically associates properies to a random object instance /// ////// 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"); /// ////// If you get 'Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo.Create' you should reference Microsoft.CSharp /// public static class ObjectExtensions { ///Stores extended data for objects private static ConditionalWeakTable
一个用法示例在xml注释中:
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