C#有扩展属性吗?
C#有扩展属性吗?
C#是否有扩展属性?
例如,我是否可以向DateTimeFormatInfo
添加一个称为ShortDateLongTimeFormat
的扩展属性,其将返回ShortDatePattern + \" \" + LongTimePattern
?
目前Roslyn编译器还不支持它...
到目前为止,扩展属性似乎还不足以被包括在前几个版本的C#标准中。各种C#版本(也许全部?)都曾提出这个提案,但它还没有发布,最重要的是,即使已经有了实现,他们也想做到正确无误。
但也许有一天会有支持...
更新2022:
这个功能似乎仍在讨论中,可以在这里找到相关内容。
此外,您也可以使用解决方法
正如本文中所指定的,您可以使用TypeDescriptor
功能在运行时将属性附加到对象实例上,但它不使用标准属性的语法。 它有点不同于仅仅是添加一个可定义扩展属性的语法糖,例如string Data(this MyClass instance)
作为扩展方法string GetData(this MyClass instance)
的别名,因为它将数据存储到类中。
我希望C#很快能提供一个全功能的扩展属性(还有字段),不过这一点只有时间才能告诉我们。
同时,请随时做出贡献,明日的软件将会源于社区。
后处理方法
如果您有权限这样做,您还可以使用像PostSharp、Mono.Cecil(或类似的代码/IL重写工具)这样的工具在编译后在您的程序集中动态添加属性。
然而,正如一个开发者在上述讨论中所解释的,重写代码不能让编译器知道您的意图,因此它可能无法优化您的代码。作为一种语言特性,结果应该更好。
历史片段
扩展成员条目在C# 7工作列表中,因此我认为它可能会在不久的将来得到支持。扩展属性的当前状态可以在Github相关项目下找到。
但是,还有一个更加有前途的话题,即“扩展一切”,特别是属性和静态类甚至字段。
更新: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的播客中提到的那样,扩展不会有任何状态(因此无法向类添加私有实例成员),这意味着您不能添加与实例关联的私有实例数据。引起这种情况的原因是它将导致内部字典的管理,并可能很困难(内存管理等)。
为此,您仍然可以使用早先描述的
语法仍可能更改,因为涉及到这个问题。例如,将扩展
可能会被取代为为
,这有些人可能会感觉更自然,也不那么与Java有关。
2018年12月更新-角色、扩展和静态接口成员
由于存在一些缺点,扩展一切并没有成为C# 8.0的一部分,这些缺点在GitHub ticket的末尾进行了说明。因此,进行了改进设计的探索。在这里,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; }