Svi*_*ish 712 c# extension-methods properties
C#有扩展属性吗?
例如,我可以添加一个扩展属性来DateTimeFormatInfo调用ShortDateLongTimeFormat哪个会返回ShortDatePattern + " " + LongTimePattern?
Jar*_*Par 424
不,它们不存在于C#3.0中,也不会在4.0中添加.它位于C#的功能需求列表中,因此可能会在将来添加.
此时,您可以做的最好的是GetXXX样式扩展方法.
Jon*_*eet 264
不,他们不存在.
我知道C#团队正在考虑他们(或者至少是Eric Lippert) - 以及扩展构造者和操作员(这些可能需要一段时间才能让你的头脑清醒,但很酷......)但是,我没有没有看到任何证据表明他们将成为C#4的一部分.
编辑:他们没有出现在C#5中,截至2014年7月,它看起来也不会出现在C#6中.
微软C#编译团队首席开发人员Eric Lippert于2012年11月在博客中发表了关于此问题的文章:
Fab*_*Fab 258
到目前为止,扩展属性被认为不足以包含在以前版本的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<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;
Run Code Online (Sandbox Code Playgroud)
与部分类类似,但在不同的程序集中编译为单独的类/类型.请注意,您也可以通过这种方式添加静态成员和运算符.如Mads Torgensen播客中所述,扩展将不具有任何状态(因此它无法将私有实例成员添加到类中),这意味着您将无法添加链接到该实例的私有实例数据.为此调用的原因是它意味着管理内部词典并且可能很难(内存管理等).为此,您仍然可以使用前面描述的TypeDescriptor/ ConditionalWeakTable技术和属性扩展,将其隐藏在一个不错的属性下.
语法仍然会发生变化,因为这意味着这个问题.例如,extends可以替换为for某些可能感觉更自然且与Java相关的更少.
更新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));
}
}
}
Run Code Online (Sandbox Code Playgroud)
然后你就可以这样做:
foreach (byte b in 0x_3A_9E_F1_C5_DA_F7_30_16ul)
{
WriteLine($"{e.Current:X}");
}
Run Code Online (Sandbox Code Playgroud)
对于静态接口:
public interface IMonoid<T> where T : IMonoid<T>
{
static T operator +(T t1, T t2);
static T Zero { get; }
}
Run Code Online (Sandbox Code Playgroud)
添加扩展属性上int和治疗int为IMonoid<int>:
public extension IntMonoid of int : IMonoid<int>
{
public static int Zero => 0;
}
Run Code Online (Sandbox Code Playgroud)
Kor*_*yem 27
更新(感谢@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;
}
}
Run Code Online (Sandbox Code Playgroud)
我们终于能够这样做......
public extension IntExtension extends int
{
public bool Even => this % 2 == 0;
}
Run Code Online (Sandbox Code Playgroud)
资料来源:https://blog.ndepend.com/c-8-0-features-glimpse-future/
正如@Psyonity所提到的,您可以使用conditionalWeakTable向现有对象添加属性.结合动态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());
}
}
Run Code Online (Sandbox Code Playgroud)
一个用法示例在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
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
193253 次 |
| 最近记录: |