15

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 IEnumerable<int> To(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 之类的框架中?

4

7 回答 7

8

我非常喜欢扩展方法,但我确实觉得当它们在 LINQ 之外使用时,它们会以牺牲可维护性为代价来提高可读性。

3.Days().FromNow()个例子。这非常具有表现力,任何人都可以阅读此代码并准确告诉您它的作用。这真是一件美好的事情。作为编码人员,我们很高兴编写具有自我描述性和表现力的代码,这样几乎不需要任何注释并且阅读起来很愉快。这段代码在这方面至关重要。

然而,作为编码人员,我们也对后代负责,我们之后的人将花费大部分时间试图理解这段代码是如何工作的。我们必须小心,不要过于表达,以至于调试我们的代码需要在无数扩展方法中跳跃。

扩展方法掩盖了“如何”以更好地表达“什么”。我想这使它们成为一把双刃剑,最好适度使用(就像所有东西一样)。

于 2008-12-16T13:55:28.550 回答
6

首先,我的直觉:3.Minutes.from_now看起来很酷,但没有说明为什么扩展方法很好。这也反映了我的普遍看法:很酷,但我从未真正错过它们。


问题:是3.Minutes时间跨度还是角度?

通过 using 语句“通常”引用的命名空间只影响类型,现在它们突然决定什么3.Minutes意思。

所以最好的就是“不让他们逃跑”。
可能被引用的命名空间中的所有公共扩展方法最终都是“某种全局的”——所有潜在的问题都与此相关。将它们保留在您的程序集内部,或者将它们放入单独的命名空间中,该命名空间分别添加到每个文件中。

于 2008-12-16T14:14:00.587 回答
5

我个人喜欢 int.To,我对 int.Days 很矛盾,我不喜欢 TimeSpan.FromNow。

我不喜欢我所认为的“流利”接口的一种时尚,它可以让你编写伪英文代码,但通过实现具有可能孤立地令人费解的名称的方法来做到这一点。

例如,这对我来说并不好读:

TimeSpan.FromSeconds(4).FromNow()

显然,这是一个主观的东西。

于 2008-12-16T13:25:19.983 回答
1

我同意 siz 的观点,并且在这个问题上倾向于保守。Rails 有这种东西,所以它从来没有那么令人困惑。当您编写“days”和“fromnow”方法时,不能保证您的代码没有错误。此外,您正在向代码添加依赖项。如果您将扩展方法放在他们自己的文件中,则每个项目中都需要该文件。在项目中,您需要在需要时包含该项目。

综上所述,对于其他框架/世界中存在的非常简单的扩展方法(例如 Jeff 对“left”的使用或 thatismatt 对 days.fromnow 的使用),我认为没关系。熟悉日期的人应该明白“3.Days().FromNow()”是什么意思。

于 2008-12-16T14:15:28.820 回答
0

我是保守派,至少目前是这样,并且反对扩展方法。对我来说,这只是语法糖,并不那么重要。我认为如果初级开发人员不熟悉 C#,这也可能是一场噩梦。我宁愿将扩展封装在我自己的对象或静态方法中。

如果您要使用它们,请不要过度使用它们,以免给自己带来方便,但会惹恼其他接触您的代码的人。:-)

于 2008-12-16T14:04:20.013 回答
0

对于语言应该是什么,每种语言都有自己的观点。Rails 和 Ruby 的设计有着各自截然不同的观点。PHP 有明显不同的意见,C(++/#) 也是如此……Vis​​ual Basic 也是如此(尽管我们显然不喜欢他们的风格)。

平衡在于拥有许多易于阅读的内置功能,而不是对所有内容的基本控制。我不希望有这么多函数,以至于每次你想做任何事情时都必须去查找(而且对于臃肿的框架肯定会有性能开销),但我个人喜欢 Rails,因为它拯救了我很多时间开发。

我想我在这里要说的是,如果您正在设计一种语言,请采取立场,从那里开始,并构建您(或您的目标开发人员)最常使用的功能。

于 2008-12-16T14:07:30.537 回答
0

我个人的偏好是暂时少用它们,然后等着看微软和其他大型组织如何使用它们。如果我们开始看到很多代码、教程和书籍都使用 3.Days().FromNow() 之类的代码,那么它就会大量使用。如果只有少数人使用它,那么您将面临代码过于难以维护的风险,因为没有足够多的人熟悉扩展的工作方式。

在相关说明中,我想知道普通 for 循环和 foreach 循环之间的性能如何比较?第二种方法似乎需要对计算机进行大量额外工作,但我对这个概念还不够熟悉,无法确定。

于 2008-12-16T14:35:22.527 回答