Rails为Ruby引入了一些核心扩展3.days.from_now
,就像你期望未来三天的日期一样.使用C#中的扩展方法,我们现在可以执行类似的操作:
static class Extensions { public static TimeSpan Days(this int i) { return new TimeSpan(i, 0, 0, 0, 0); } public static DateTime FromNow(this TimeSpan ts) { return DateTime.Now.Add(ts); } } class Program { static void Main(string[] args) { Console.WriteLine( 3.Days().FromNow() ); } }
或者怎么样:
static class Extensions { public static IEnumerableTo(this int from, int to) { return Enumerable.Range(from, to - from + 1); } } class Program { static void Main(string[] args) { foreach (var i in 10.To(20)) { Console.WriteLine(i); } } }
这是根本错误的,还是有时它是一个好主意,比如像Rails这样的框架?
我非常喜欢扩展方法,但我觉得当它们在LINQ之外使用时,它们以可维护性为代价提高了可读性.
以3.Days().FromNow()
作为一个例子.这非常具有表现力,任何人都可以阅读此代码并准确地告诉您它的作用.这是一件非常美好的事情.作为编码员,我们喜欢编写自我描述和表达的代码,因此它几乎不需要任何评论,并且很高兴阅读.在这方面,此代码至关重要.
然而,作为编码员,我们也对后代负责,而那些追随我们的人将花费大部分时间来试图理解这段代码的工作原理.我们必须小心,不要那么表达,调试我们的代码需要在无数的扩展方法中跳跃.
扩展方法揭示"如何"更好地表达"什么".我想这使得它们成为一把双刃剑,最适合(如同所有事情)适度使用.
首先,我的直觉:3.Minutes.from_now
看起来很酷,但没有证明为什么扩展方法是好的.这也反映了我的一般观点:很酷,但我从来没有真正错过它们.
问题:是3.Minutes
时间跨度还是角度?
通过using语句"正常"引用的命名空间仅影响类型,现在它们突然决定了什么3.Minutes
意思.
所以最好是"不要让他们逃脱".
可能被引用的命名空间中的所有公共扩展方法最终都是"全球化的" - 与此相关的所有潜在问题.将它们保留在程序集内部,或将它们放入单独的命名空间中,该命名空间将单独添加到每个文件中.
我个人喜欢int.To,我对int.Days感到矛盾,我不喜欢TimeSpan.FromNow.
我不喜欢我所看到的"流畅"界面的一点时尚,它让你编写伪英文代码,但通过实现名称可能孤立无助的方法来实现.
例如,这对我来说不太好看:
TimeSpan.FromSeconds(4).FromNow()
显然,这是一个主观的事情.