你应该在C#4.0中使用重载或可选参数声明方法吗?

Gre*_*ech 91 c# overloading optional-parameters c#-4.0

我正在观看Anders关于C#4.0的讨论和C#5.0的预览,它让我想到C#中何时可以提供可选参数什么是推荐的方法来声明不需要指定所有参数的方法?

例如,FileStream类这样的东西有大约十五种不同的构造函数,它们可以分为逻辑"族",例如下面的字符串,来自a的那些IntPtr和来自a的那些SafeFileHandle.

FileStream(string,FileMode);
FileStream(string,FileMode,FileAccess);
FileStream(string,FileMode,FileAccess,FileShare);
FileStream(string,FileMode,FileAccess,FileShare,int);
FileStream(string,FileMode,FileAccess,FileShare,int,bool);
Run Code Online (Sandbox Code Playgroud)

在我看来,这种类型的模式可以通过改为使用三个构造函数来简化,并使用可以默认的参数的可选参数,这将使构造函数的不同系列更加清晰[注意:我知道这个更改不会是在BCL制作,我正在假设这种情况].

你怎么看?从C#4.0开始,将具有可选参数的紧密相关的构造函数和方法组作为单一方法更有意义,还是有充分理由坚持使用传统的多重载荷机制?

Jon*_*eet 115

我考虑以下几点:

  • 您是否需要从不支持可选参数的语言中使用您的代码?如果是这样,请考虑包含重载.
  • 您的团队中是否有任何成员强烈反对可选参数?(有时候,与你不喜欢的决定相比,生活更容易,而不是争辩.)
  • 您是否确信您的默认值不会在代码构建之间发生变化,或者如果可能,您的呼叫者是否可以接受?

我还没有检查默认值是如何工作的,但我假设默认值将被烘焙到调用代码中,与对const字段的引用非常相似.这通常没问题 - 无论如何,更改为默认值非常重要 - 但这些都是需要考虑的事情.

  • +1实用主义的智慧:_有时候你更喜欢与你不喜欢的决定生活在一起. (16认同)
  • @romkyns:不,重载的效果与第3点不同.由于重载提供了默认值,默认值是*在库代码中* - 所以如果更改默认值并提供库的新版本,调用者将看到新的默认值而无需重新编译.使用可选参数时,您需要重新编译以"查看"新的默认值.很多时候它不是一个重要的区别,但它*是一个区别. (12认同)

cfe*_*uke 17

当方法重载通常使用不同数量的参数执行相同的操作时,将使用默认值.

当方法重载根据其参数执行不同的函数时,将继续使用重载.

我在VB6的日子里使用了可选的版本,从那以后就错过了它,它会减少C#中的大量XML注释重复.


Ian*_*oyd 11

我一直在使用带有可选参数的Delphi.我转而使用重载代替了.

因为当你去创造更多的重载时,你总会用一个可选的参数形式来识别; 然后你必须将它们转换为非可选的.

我喜欢这样的概念:通常有一种超级方法,其余的是围绕那种方法更简单的包装.

  • 我非常同意这一点,但是需要注意的是,当您有一个采用多个(3+)参数的方法时,这些参数本质上都是“可选”(可以用默认值代替),您最终可能会得到许多排列方法签名没有更多好处。考虑“Foo(A, B, C)”需要“Foo(A)”、“Foo(B)”、“Foo(C)”、“Foo(A, B)”、“Foo(A, C)” ,`Foo(B,C)`。 (2认同)

JP *_*oto 7

我一定会使用4.0的可选参数功能.它摆脱了荒谬......

public void M1( string foo, string bar )
{
   // do that thang
}

public void M1( string foo )
{
  M1( foo, "bar default" ); // I have always hated this line of code specifically
}
Run Code Online (Sandbox Code Playgroud)

...并将值放在呼叫者可以看到的位置......

public void M1( string foo, string bar = "bar default" )
{
   // do that thang
}
Run Code Online (Sandbox Code Playgroud)

更简单,更不容易出错.我实际上已经将此视为过载情况下的错误...

public void M1( string foo )
{
   M2( foo, "bar default" );  // oops!  I meant M1!
}
Run Code Online (Sandbox Code Playgroud)

我还没有使用4.0编译器,但我不会感到震惊,因为编译器只是为你发出重载.


sup*_*cat 6

可选参数本质上是一段元数据,它指示处理方法调用的编译器在调用站点插入适当的默认值.相比之下,重载提供了一种方法,通过该方法,编译器可以选择多种方法中的一种,其中一些方法本身可能提供默认值.请注意,如果尝试从不支持它们的语言编写的代码中调用指定可选参数的方法,则编译器将要求指定"可选"参数,但由于调用方法而未指定可选参数,相当于使用等于默认值的参数调用它,这些语言调用这些方法没有任何障碍.

在调用站点绑定可选参数的一个重要结果是,它们将根据编译器可用的目标代码的版本分配值.如果程序集Foo的方法Boo(int)具有默认值5,并且程序集Bar包含对其的调用Foo.Boo(),则编译器将其处理为a Foo.Boo(5).如果默认值更改为6并Foo重新编译程序集,Bar则将继续调用,Foo.Boo(5)除非或直到使用该新版本重新编译它Foo.因此,应该避免对可能发生变化的事物使用可选参数.


mr.*_*r.b 5

是否应该使用可选参数或重载可以争论,但最重要的是,每个参数都有自己不可替代的领域。

可选参数与命名参数结合使用时,与 COM 调用的一些长参数列表和所有可选参数结合使用时非常有用。

例如,当方法能够对许多不同的参数类型(只是示例之一)进行操作时,重载非常有用,并且在内部进行转换;你只需用任何有意义的数据类型(被一些现有的重载接受)提供它。不能用可选参数打败它。