Console.WriteLine()和那么多参数重载的必要性是什么?

87

我正在查阅文档,发现 Console.WriteLine() 方法有多个重载。特别是,我对以下内容感到好奇和有些困惑:

public static void WriteLine(string format, params object[] arg);
public static void WriteLine(string format, object arg0);
public static void WriteLine(string format, object arg0, object arg1);
public static void WriteLine(string format, object arg0, object arg1, object arg2);
public static void WriteLine(string format, object arg0, object arg1, object arg2, object arg3);

看起来有些冗余。除了第一个方法,其他四个重载方法的需要是什么?第一个方法能够完成其他方法可以完成的所有任务。他们提供额外的重载是否是为了解决性能问题,这些重载处理多达四个参数(最后一个)?通过遍历高达四个参数的数组的开销足以提供对这些重载的需求吗?

5个回答

102

一般来说,第一个重载可以满足其他重载的需求。但是这并不是严格正确的,因为params关键字不能用于间接情况,比如方法组绑定。例如:

delegate void E(string format, object o1);
E e = Console.WriteLine;

params 的重载无法满足这种情况,它只能在存在特定的重载时才起作用。

public static void WriteLine(string format, object arg0);

虽然那是一个相当深奥的案例,但更重要的原因如下:

  1. 并非所有 CLI 语言都需要支持 params 关键字。拥有重载可以减轻这些语言的负担,无需为简单的 WriteLine` 调用手动创建数组。
  2. 性能。调用 params 重载会强制调用者分配一个数组,即使编译器隐式执行。在 .Net 中,分配是便宜的,但不是免费的。像 Console.WriteLine 这样常被调用的方法,小细节会很快累积。拥有其他重载可以避免这种分配,使常见情况得到优化。

1
我在回答中考虑了方法组的情况,但我相当确定方法组转换是在C# 2.0之后引入的,而WriteLine重载至少可以追溯到1.1。 - jaket
@jaket 方便的语法是在C# 2.0中添加的。但是,如果您在C# 1中使用显式的new E(Console.WriteLine),则同样适用。 - CodesInChaos
5
在使用Console.WriteLine时,数组分配是否会有明显影响? - Bryan Boettcher
3
@insta,问题不在于速度,而在于分配的累积。垃圾回收虽然廉价但并非免费,在复杂的应用程序中,垃圾回收通常是主要的性能瓶颈。停止常见的无需分配的来源对于性能至关重要。 - JaredPar

38

这些重载是为了方便C++/CLI程序而存在的,因为它们不支持params关键字。


1
这是一个很棒的回答,对于一个很棒的问题,以我个人的看法。 - Uwe Keim
1
啊...这其实很有道理。我真是太丢人了,C++是我的第一门语言。 :) - B.K.
3
从第一门语言开始,基础知识就开始了。聪明的伙计,机智的回答。 - Deepak Bhatia

4

我认为你们所有人都忘记了,params是在C#2.0中引入的。因此,当params关键字不存在时,重载也存在于.NET 1.1中。


jaket 提到了。 - B.K.
阅读他对JaredPar答案的评论。这就是他没有在自己的答案中包含参数解释的原因之一。 - B.K.
@Noobacode,他确实这样做了,但我理解是推断出来的。我在这里给Alan点赞(尽管这只值得那么一点点),因为他用更直接的方式陈述了这个问题。 - Frank V
1
从这个链接中可以看出,params关键字在.Net 1.1中也存在。 - Sriram Sakthivel

1
我认为所问问题已被JaredParjaket提供了良好且详细的答案,但我认为还有一个点也很重要,那就是我认为用户使用任何上述功能的便利性和自由度,根据他们的需求、方式和需要使用任何一种功能都比强制他们创建一个数组更加方便。
我想到了我开始学习C#的旧日子,我几乎没有使用过数组,而使用数组对我来说是一项复杂的任务,分配它们并用适当的值初始化它们真的非常复杂和耗时...

3
params的概念在于你可以传递一个数组,或者明确地写出所有参数。像void do(params object[])这样的方法既可以通过do(new object[] {"some", "stuff"}进行调用,也可以通过do("some", "stuff")进行调用。我认为你的观点在这里并不完全适用。 - Kroltan
2
@Kroltan 但是你能告诉我有多少初学者真正了解 params 的含义,以及他们知道如果有 params,那么可以将变量作为逗号分隔的方式传递。 - Deepak Bhatia
1
@Kroltan 我也很长一段时间不知道 params 的用法可以像这样,如果在 Visual Studio 的帮助部分中看到 array [] 作为参数,我会认为提供数组作为参数是正确的... - Deepak Bhatia

-3

这并不是为了性能问题而做出的决定。然而,提高可用性是一个合理的原因。

下面的代码将为您提供一些见解。

public class TipCalculator {
    private const double tipRate = 0.18;
    public static int Main(string[] args) {
        double billTotal;
        if (args.Length == 0) {
            Console.WriteLine("usage: TIPCALC total");
            return 1;
        }
        else {
            try {
                billTotal = Double.Parse(args[0]);
            }
            catch(FormatException) {
                Console.WriteLine("usage: TIPCALC total");
                return 1;
            }
            double tip = billTotal * tipRate;
            Console.WriteLine();
            Console.WriteLine("Bill total:\t{0,8:c}", billTotal);
            Console.WriteLine("Tip total/rate:\t{0,8:c} ({1:p1})", tip, tipRate);
            Console.WriteLine(("").PadRight(24, '-'));
            Console.WriteLine("Grand total:\t{0,8:c}", billTotal + tip);
            return 0;
        }
    }
}

请参考链接:http://msdn.microsoft.com/en-us/library/aa324774(v=vs.71).aspx 了解更多信息。

9
增加可用性的方法是什么?第一种方法可以完全做到与其他四种方法相同的效果。你让我查阅文档,但我已经在查阅文档了。我知道这个方法用于什么以及如何使用(我对C#并不陌生)。但为什么需要在第一个方法的基础上增加额外的重载呢? - B.K.
我认为他的意思是,如果只传递一个参数,那么创建一个数组来保存它并将其传递给方法是没有意义的 - 为什么不直接传递一个参数呢?这就是我这样做的原因。 - KingTravisG
@SCassidy1986:当参数是params方法时,你不需要手动创建数组,除非你想要。编译器会自动创建一个数组。这就是params和这个问题的意义所在。 - Magus

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接