C# 有扩展属性吗?
例如,我可以将扩展属性添加到DateTimeFormatInfo调用ShortDateLongTimeFormatwhich 会返回ShortDatePattern + " " + LongTimePattern吗?
DateTimeFormatInfo
ShortDateLongTimeFormat
ShortDatePattern + " " + LongTimePattern
到目前为止,扩展属性的价值还不足以包含在以前版本的 C# 标准中。 C# 7 和 C# 8.0 已将此视为提案冠军,但尚未发布,最重要的是,即使已经有实现,他们也希望从一开始就做好。
C# 7 工作列表 中有一个 扩展成员 项,因此它可能会在不久的将来得到支持。扩展属性的当前状态可以在Github 的相关项下找到。
然而,还有一个更有希望的主题是“扩展一切”,特别关注属性和静态类甚至字段。
如本文所述,您可以使用TypeDescriptor在运行时将属性附加到对象实例的功能。但是,它没有使用标准属性的语法。 它与仅仅添加了定义扩展属性的可能性的语法糖有点不同,例如 string Data(this MyClass instance)作为扩展方法的别名, string GetData(this MyClass instance)因为它将数据存储到类中。
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<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;
类似于部分类,但在不同的程序集中编译为单独的类/类型。请注意,您还可以通过这种方式添加静态成员和运算符。正如Mads Torgensen 播客中提到的, 扩展不会有任何状态(因此它不能将私有实例成员添加到类中),这意味着您将无法添加链接到实例的私有实例数据 。为此调用的原因是它意味着管理内部字典并且可能很困难(内存管理等)。为此,您仍然可以使用前面描述的TypeDescriptor/ConditionalWeakTable技术,并使用属性扩展,将其隐藏在一个不错的属性下。
ConditionalWeakTable
正如这个问题所暗示的那样,语法仍然会发生变化。例如,extends可以替换为for某些可能感觉更自然且与 java 相关性较低的部分。
extends
for
2018 年 12 月更新 - 角色、扩展和静态界面成员
扩展一切都 没有进入 C# 8.0,因为一些缺点解释为这个GitHub 票的结尾。因此,进行了改进设计的探索。在这里,Mads Torgensen 解释了什么是 角色和扩展 以及它们之间的区别:
角色允许在给定类型的特定值上实现接口。扩展允许在特定代码区域内对给定类型的所有值实现接口。
可以从两个用例中的先前提案的拆分中看出。扩展的 新语法 如下:
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)); } } }
那么你就可以做到这一点:
foreach (byte b in 0x_3A_9E_F1_C5_DA_F7_30_16ul) { WriteLine($"{e.Current:X}"); }
对于 静态接口 :
public interface IMonoid<T> where T : IMonoid<T> { static T operator +(T t1, T t2); static T Zero { get; } }
在上添加 扩展属性int并将其int视为IMonoid<int>:
int
IMonoid<int>
public extension IntMonoid of int : IMonoid<int> { public static int Zero => 0; }