C#可选参数或方法重载?

Luk*_*ina 24 c# coding-style overloading optional-parameters

由于C#添加了可选参数,因此使用可选参数或方法重载被认为是更好的做法,或者是否存在您希望使用其中一个的特定情况.即具有许多参数的函数更适合w /可选参数?

Chu*_*way 20

可选参数很好,但应该在有意义的时候使用.可选参数通常会使方法的意图变得混乱 - 如果有另一种选择,我会倾向于替代方案.

可选参数和命名参数的部分需求是因为COM允许可选参数和名称参数:

MSDN

一些API,尤其是COM接口,例如Office自动化API,是专门针对命名和可选参数编​​写的.到目前为止,从C#调用这些API非常痛苦,有时需要显式传递多达30个参数,其中大多数具有合理的默认值并且可以省略.

来自forums.asp.net的SomeNewKid简明扼要地说:

http://forums.asp.net/t/386604.aspx/1

...重载方法通常优于可选参数.为什么?保持每个方法的目的明确.也就是说,每种方法都应该做好一件事.一旦引入可选参数,就会稀释该方法的清洁度,并引入可能最好远离方法的分支逻辑.当您开始使用继承时,这种目的明确性变得更加重要.如果覆盖具有一个或多个可选参数的方法,则它们将变得更难以使用.所以,我建议除了快速和脏类之外的其他任何东西,你可以使用重载优先于可选参数.

请记住,可选参数是语法糖:

反射器C#:

public class Class1
{
    // Methods
    public Class1()
    {
        this.Method1("3", "23");
    }

    public void Method1(string one, [Optional, DefaultParameterValue("23")] string two)
    {
    }
}
Run Code Online (Sandbox Code Playgroud)

IL:

.class public auto ansi beforefieldinit Class1
    extends [mscorlib]System.Object
{
    .method public hidebysig specialname rtspecialname instance void .ctor() cil managed
    {
        .maxstack 8
        L_0000: ldarg.0 
        L_0001: call instance void [mscorlib]System.Object::.ctor()
        L_0006: nop 
        L_0007: nop 
        L_0008: ldarg.0 
        L_0009: ldstr "3"
        L_000e: ldstr "23"
        L_0013: call instance void WebApplication1.Class1::Method1(string, string)
        L_0018: nop 
        L_0019: nop 
        L_001a: ret 
    }

    .method public hidebysig instance void Method1(string one, [opt] string two) cil managed
    {
        .param [2] = string('23')
        .maxstack 8
        L_0000: nop 
        L_0001: ret 
    }

}
Run Code Online (Sandbox Code Playgroud)

  • 我不知道,根据我的经验,16次超载是_really_肮脏的水.相比之下,4个可选参数不那么混乱.当然,这是一个极端的例子,但我不知道你的平均重载集是如何做出像SomeNewKid的理想主义引用; 你通常会得到2ⁿ重载n =有多少可选参数.如果您发现自己这样做,请使用可选参数代替. (7认同)

Ror*_*eod 11

Visual Studio和FxCop中的代码分析建议您不要在公共API中使用可选参数(规则CA1026:不应使用默认参数).给出的理由是并非所有.NET语言都支持它们.

我认为避免它们的一个更好的理由是,如果在API的2.0版本中添加更多重载,它们可能会引入运行时或编译时问题.Phil Haack在这里解释道.

我将采用Phil的结论:可选参数旨在支持COM互操作; 如果你不使用COM,请不要管它们.

  • 如果*您正在构建公共API,这些都是很好的分数.对于内部方法,"规则"显然是完全不同的,尽管有些人确实选择遵循API设计指南,即使是内部方法.哪个也好. (3认同)

hem*_*emp 10

我不确定这是否有规范的答案 - 它是主观的,逐案的.但是,在我看来,可选参数创建了更明确的API,因此,我通常更喜欢它们而不是方法重载.

具体来说,在使用Intellisense时,我更喜欢看到这个:

带有默认值的可选参数

在此:

超载1

超载2

超载3

如果我没有指定,我可能需要猜测(或查找文档)param1和param2的值.

  • 使用可选参数的@hemp会产生歧义.你最终会得到一种能做很多事情的方法.该方法将根据其输入具有不同的行为.一种方法应该只做一件事,一件事. (8认同)
  • @Chuck我全心全意地不同意,这就是为什么我开始说这个问题本质上是主观的.此外,"一种方法应该只做一件事,一件事情"的论点是一个疲惫而且经常被滥用的论点.更糟糕的是,我看到的重载方法的最常见的实现*模式是让一个重载调用另一个,传入一个默认值. (8认同)
  • @Chuck无法解决"歧义"问题,因为这纯粹是主观的.但是,使用重载方法来设置默认值会违反您在方法中具有分支逻辑的位置,因为该方案中的最终被调用者根据传入的值表现不同. (3认同)
  • 虽然我同意"一件事"的方法是计算机科学课程,但多重载方法的提取确实有意义.每个重载都应该被视为具有不同参数验证甚至逻辑的用例.如上所述,它在很大程度上是暗示性的,但我发现将可选参数的简洁用例作为kludge,并且意味着为开发一些有趣的bug提供一个嵌套.测试一系列重载比在很多情况下提出可选参数的所有可能排列要容易得多. (3认同)
  • @joseph:谢谢你的深思熟虑的评论.我当然同意创建具有许多可选参数排列的方法是一个问题,但我认为这同样适用于重载方法的排列.例如,如果您有12个具有相同名称的方法,那么该名称如何能够充分描述所有12种方法的行为?这是一种代码气味和测试挑战(无论是通过重载还是可选参数实现). (3认同)