您应该在 C# 4.0 中使用重载还是可选参数来声明方法?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/251868/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-03 20:00:02  来源:igfitidea点击:

Should you declare methods using overloads or optional parameters in C# 4.0?

c#c#-4.0overloadingoptional-parameters

提问by Greg Beech

I was watching Anders' talk about C# 4.0 and sneak preview of C# 5.0, and it got me thinking about when optional parameters are available in C# what is going to be the recommended way to declare methods that do not need all parameters specified?

我正在观看Anders 谈论 C# 4.0 和 C# 5.0 的先睹为快,这让我开始思考何时在 C# 中提供可选参数,什么是声明不需要指定所有参数的方法的推荐方法?

For example something like the FileStreamclass has about fifteen different constructors which can be divided into logical 'families' e.g. the ones below from a string, the ones from an IntPtrand the ones from a SafeFileHandle.

例如,FileStream类有大约 15 个不同的构造函数,它们可以分为逻辑“族”,例如下面的那些来自字符串、来自 anIntPtr的那些和来自 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);

It seems to me that this type of pattern could be simplified by having three constructors instead, and using optional parameters for the ones that can be defaulted, which would make the different families of constructors more distinct [note: I know this change will not be made in the BCL, I'm talking hypothetically for this type of situation].

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

What do you think? From C# 4.0 will it make more sense to make closely related groups of constructors and methods a single method with optional parameters, or is there a good reason to stick with the traditional many-overload mechanism?

你怎么认为?从 C# 4.0 开始,让密切相关的构造函数和方法组成为具有可选参数的单个方法是否更有意义,或者是否有充分的理由坚持传统的多次重载机制?

采纳答案by Jon Skeet

I'd consider the following:

我会考虑以下几点:

  • Do you need your code to be used from languages which don't support optional parameters? If so, consider including the overloads.
  • Do you have any members on your team who violently oppose optional parameters? (Sometimes it's easier to live with a decision you don't like than to argue the case.)
  • Are you confident that your defaults won't change between builds of your code, or if they might, will your callers be okay with that?
  • 您是否需要在不支持可选参数的语言中使用您的代码?如果是这样,请考虑包括重载。
  • 您的团队中是否有成员强烈反对可选参数?(有时接受一个你不喜欢的决定比争论这个案子更容易。)
  • 您是否确信您的默认设置不会在您的代码构建之间发生变化,或者如果可能,您的调用者会同意吗?

I haven't checked how the defaults are going to work, but I'd assume that the default values will be baked into the calling code, much the same as references to constfields. That's usually okay - changes to a default value are pretty significant anyway - but those are the things to consider.

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

回答by cfeduke

When a method overload normally performs the same thing with a different number of arguments then defaults will be used.

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

When a method overload performs a function differently based on its parameters then overloading will continue to be used.

当方法重载根据其参数以不同方式执行功能时,将继续使用重载。

I used optional back in my VB6 days and have since missed it, it will reduce a lot of XML comment duplication in C#.

我在我的 VB6 时代使用了 optional 并且后来错过了它,它将减少 C# 中的大量 XML 注释重复。

回答by Mark A. Nicolosi

I'm looking forward to optional parameters because it keeps what the defaults are closer to the method. So instead of dozens of lines for the overloads that just call the "expanded" method, you just define the method once and you can see what the optional parameters default to in the method signature. I'd rather look at:

我期待可选参数,因为它保留了更接近方法的默认值。因此,与仅调用“扩展”方法的重载的几十行不同,您只需定义该方法一次,您就可以在方法签名中看到可选参数的默认值。我宁愿看:

public Rectangle (Point start = Point.Zero, int width, int height)
{
    Start = start;
    Width = width;
    Height = height;
}

Instead of this:

取而代之的是:

public Rectangle (Point start, int width, int height)
{
    Start = start;
    Width = width;
    Height = height;
}

public Rectangle (int width, int height) :
    this (Point.Zero, width, height)
{
}

Obviously this example is really simple but the case in the OP with 5 overloads, things can get crowded real quick.

显然,这个例子非常简单,但在 OP 中有 5 个重载的情况下,事情会很快变得拥挤。

回答by JP Alioto

I will definitely be using the optional parameters feature of 4.0. It gets rid of the ridiculous ...

我肯定会使用 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
}

... and puts the values right where the caller can see them ...

... 并将值放在调用者可以看到的地方 ...

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

Much more simple and much less error prone. I've actually seen this as a bug in the overload case ...

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

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

I have not played with the 4.0 complier yet, but I would not be shocked to learn that the complier simply emits the overloads for you.

我还没有玩过 4.0 编译器,但得知编译器只是为您发出重载,我不会感到震惊。

回答by Ian Boyd

I've been using Delphi with optional parameters forever. I've switched to using overloads instead.

我一直在使用带有可选参数的 Delphi。我已经改用重载了。

Because when you go to create more overloads, you'll invariably conflict with an optional parameter form, and then you'll have to convert them to non-optional anyway.

因为当你去创建更多的重载时,你总会与可选参数形式发生冲突,然后你无论如何都必须将它们转换为非可选。

And I like the notion that there's generally one supermethod, and the rest are simpler wrappers around that one.

而且我喜欢这样一种观点,即通常只有一种超级方法,其余的都是围绕该方法的更简单的包装器。

回答by mr.b

It can be argued whether optional arguments or overloads should be used or not, but most importantly, each have their own area where they are irreplaceable.

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

Optional arguments, when used in combination with named arguments, are extremely useful when combined with some long-argument-lists-with-all-optionals of COM calls.

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

Overloads are extremely useful when method is able to operate on many different argument types (just one of examples), and does castings internally, for instance; you just feed it with any data type that makes sense (that is accepted by some existing overload). Can't beat that with optional arguments.

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

回答by sushil pandey

Both Optional parameter , Method overload have there own advantage or disadvantage.it depends on your preference to choose between them.

可选参数,方法重载都有自己的优点或缺点。这取决于您在它们之间进行选择的偏好。

Optional Parameter: available only in .Net 4.0. optional parameter reduce your code size. You can't define out and ref parameter

可选参数:仅在 .Net 4.0 中可用。可选参数减少您的代码大小。您不能定义 out 和 ref 参数

overloaded methods: You can Define Out and ref parameters. Code size will increase but overloaded method's are easy to understand.

重载方法:您可以定义 Out 和 ref 参数。代码大小会增加,但重载的方法很容易理解。

回答by supercat

Optional parameters are essentially a piece of metadata which directs a compiler that's processing a method call to insert appropriate defaults at the call site. By contrast, overloads provide a means by which a compiler can select one of a number of methods, some of which might supply default values themselves. Note that if one tries to call a method that specifies optional parameters from code written in a language which doesn't support them, the compiler will require that the "optional" parameters be specified, but since calling a method without specifying an optional parameter is equivalent to calling it with a parameter equal to the default value, there's no obstacle to such languages calling such methods.

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

A significant consequence of binding of optional parameters at the call site is that they will be assigned values based upon the version of the target code which is available to the compiler. If an assembly Foohas a method Boo(int)with a default value of 5, and assembly Barcontains a call to Foo.Boo(), the compiler will process that as a Foo.Boo(5). If the default value is changed to 6 and assembly Foois recompiled, Barwill continue to call Foo.Boo(5)unless or until it is recompiled with that new version of Foo. One should thus avoid using optional parameters for things that might change.

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

回答by Zoran Horvat

In many cases optional parameters are used to switch execution. For example:

在许多情况下,可选参数用于切换执行。例如:

decimal GetPrice(string productName, decimal discountPercentage = 0)
{

    decimal basePrice = CalculateBasePrice(productName);

    if (discountPercentage > 0)
        return basePrice * (1 - discountPercentage / 100);
    else
        return basePrice;
}

Discount parameter here is used to feed the if-then-else statement. There is the polymorphism that wasn't recognized, and then it was implemented as an if-then-else statement. In such cases, it is much better to split the two control flows into two independent methods:

此处的折扣参数用于提供 if-then-else 语句。存在未被识别的多态性,然后将其实现为 if-then-else 语句。在这种情况下,最好将两个控制流拆分为两个独立的方法:

decimal GetPrice(string productName)
{
    decimal basePrice = CalculateBasePrice(productName);
    return basePrice;
}

decimal GetPrice(string productName, decimal discountPercentage)
{

    if (discountPercentage <= 0)
        throw new ArgumentException();

    decimal basePrice = GetPrice(productName);

    decimal discountedPrice = basePrice * (1 - discountPercentage / 100);

    return discountedPrice;

}

In this way, we have even protected the class from receiving a call with zero discount. That call would mean that the caller thinks that there is the discount, but in fact there is no discount at all. Such misunderstanding can easily cause a bug.

通过这种方式,我们甚至保护了班级免于接到零折扣的电话。那个电话意味着来电者认为有折扣,但实际上根本没有折扣。这种误解很容易导致错误。

In cases like this, I prefer not to have optional parameters, but to force the caller explicitly select the execution scenario that suits its current situation.

在这种情况下,我宁愿没有可选参数,而是强制调用者明确选择适合其当前情况的执行场景。

The situation is very similar to having parameters that can be null. That is equally bad idea when implementation boils to statements like if (x == null).

这种情况非常类似于参数可以为空。当实现归结为诸如if (x == null).

You can find detailed analysis on these links: Avoiding Optional Parametersand Avoiding Null Parameters

您可以在这些链接上找到详细分析:Avoiding Optional ParametersAvoiding Null Parameters

回答by HimBromBeere

One of my favourites aspects of optional parameters is that you see what happens to your parameters if you do not provide them, even without going to the method definition. Visual Studio will simply show you the default valuefor the parameter when you type the method name. With an overload method you are stuck with either reading the documentation (if even available) or with directly navigating to the method's definition (if available) and to the method that the overload wraps.

我最喜欢的可选参数方面之一是,即使不转到方法定义,您也可以看到如果不提供参数会发生什么情况。当您键入方法名称时,Visual Studio 将简单地向您显示参数的默认值。对于重载方法,您要么阅读文档(如果可用),要么直接导航到方法的定义(如果可用)和重载包装的方法。

In particular: the documentation effort may increase rapidly with the amount of overloads, and you will probably end up copying already existing comments from the existing overloads. This is quite annoying, as it does not produce any value and breaks the DRY-principle). On the other hand, with an optional parameter there's exactly one placewhere all the parameters are documented and you see their meaning as well as their default valueswhile typing.

特别是:文档工作可能会随着重载的数量而迅速增加,并且您可能最终会从现有的重载中复制已经存在的注释。这很烦人,因为它不会产生任何价值并违反DRY 原则)。另一方面,对于可选参数,正好有一个地方记录了所有参数,您可以在键入时看到它们的含义以及它们的默认值

Last but not least, if you are the consumer of an API you may not even have the option of inspecting the implementation details (if you don't have the source code) and therefore have no chance to see to which super method the overloaded ones are wrapping. Thus you're stuck with reading the doc and hoping that all default values are listed there, but this is not always the case.

最后但并非最不重要的是,如果您是 API 的使用者,您甚至可能无法检查实现细节(如果您没有源代码),因此没有机会看到重载的超级方法正在包装。因此,您一直在阅读文档并希望在那里列出所有默认值,但情况并非总是如此。

Of course, this is not an answer that handles all aspects, but I think it adds one which has not be covered so far.

当然,这不是一个处理所有方面的答案,但我认为它增加了一个迄今为止尚未涵盖的内容。