函数重载 vs 可选参数

4

我在思考函数重载...

重载方法具有相同的名称但具有唯一的签名。参数数量、参数类型或两者都必须不同。一个函数无法仅基于不同的返回类型进行重载。

那么在下面的例子中,为什么要重载 setName 而不是使用中间和姓氏值的可选参数?

class funOverload
{
    public string name;

    //overloaded functions
    public void setName(string last)
    {
        name = last;
    }

    public void setName(string first, string last)
    {
        name = first + "" + last;
    }

    public void setName(string first, string middle, string last)
    {
        name = first + "" + middle + "" + last;
    }

    //Entry point
    static void Main(string[] args)
    {
        funOverload obj = new funOverload();

        obj.setName("barack");
        obj.setName("barack "," obama ");
        obj.setName("barack ","hussian","obama");

    }
}

至少,使用以下内容可以减少需要编写的代码量:

public void setName(string first, string middle = "", string last = "")
{
   name = first + "" + middle + "" + last;

   // name = "barack" + "" + "";
}

//Entry point
static void Main(string[] args)
{
    funOverload obj = new funOverload();

    // could optionally set middle and last name values here as well
    obj.setName("barack");
 }

我理解重载的概念,但我不明白为什么它会比使用可选参数更可取(或反之亦然)。
有人可以解释一下吗?
仅供参考,这是我曾经重载过的第一个函数:http://pastebin.com/ynCuaay1。此函数允许您调用带参数或不带参数的MySqlContext.GetReader()。我认为这使代码变得更整洁,而不必每次都调用GetReader(sql, args.ToArray())

这得视情况而定,可选参数对于之前的过载函数非常有用,并且只需要使用额外参数的默认值进行调用。在这种情况下,它们很适合使用,但有些地方不适用(例如在内部使用XmlWriter但可以采用TextWriter的情况下),比如XDocument.Save。 - It'sNotALie.
除了其他评论之外,可选参数直到C# 4.0才可用,我们这些在早期版本上学习的人习惯于编写重载函数。 - Jcl
3
可选参数更适用于有明智或通用的默认值存在的情况。而函数重载则表示您实际上有几种形式的同一函数,取决于某些参数信息的存在性。在大多数情况下,两者都可以使用,但在特定上下文中,其中一个可能会更加清晰明了。 - lurker
2
还有一些有趣的小细节;可选参数在编译时解析。因此,如果您针对具有 string middle = "" 的 DLL 进行编译,然后将其替换为具有 string middle = null 的更新版本,而不重新编译,则仍会输入空字符串。此外,在继承/接口方面,没有任何虚拟/签名的内容。如果声明了 MyInterface.Foo(string x = null),则实现可以声明 MyClass.Foo(string x = "default"),调用者将根据对象的已知类型编译/传递一个值。 - Chris Sinclair
如果你正在编写一个供第三方使用的库,使用重载而不是可选参数可能会更有优势,因为你可以虚拟化或更改它们的行为,而不强制消费者重新编译代码。(编辑:此外,消费者不必总是知道“默认”值是什么)当我有多个可选参数且允许以任何组合时,我倾向于使用可选参数。提供所有重载可能过度或不可能(由于签名基于参数类型而不是参数名称,因此您不能有超过3个字符串组合的一种)。 - Chris Sinclair
显示剩余3条评论
2个回答

1

我不明白的是,为什么它比使用可选参数更具有吸引力

具有默认值的参数在某些情况下存在一些限制,这些限制可能在某些情况下非常重要。

您可以为引用类型设置默认参数,而不是 null(除了 string 参数):

class Foo
{
    public int Id { get; set; }
}

class Bar
{
    public Bar(Foo parent)
    {
    }

    public Bar()
        : this(new Foo { Id = 1 }) // this can't be done with default parameters
    {
    }
}

默认值参数不能出现在普通参数之前,尽管有时这样做是合适的:

class Foo
{
    public void Method(int i, string s, bool b) { }
    public void Method(string s, bool b) 
    {
        Method(0, s, b); // this can't be done with default parameters
    }
}

0
在您的示例中,这三个重载方法与具有可选参数的方法并不等效。 setName(string last) 表示给定的最小数据是姓氏,而 public void setName(string first, string middle = "", string last = "") 不允许您省略名字。如果您想在调用具有可选参数的方法时省略中间名,则必须使用 setName("barack", last: "obama")

最好将具有可选参数的方法编写为:

public void setName(string last, string first= "", string middle = "")

但是这破坏了名称的自然顺序,允许你设置没有指定第一个名字的中间名(setName("barack", middle: "hussein");),而这三个重载都禁止了这种情况。


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