【问题标题】:Is it OK to change values of optional parameters是否可以更改可选参数的值
【发布时间】:2015-07-28 11:59:01
【问题描述】:

更改参数值被认为是一种反模式,但我发现它有时对 C# 中的可选参数很有用:

public void Foo(int p1, MyClass fooObj = null)
{
    if (fooObj == null)
    {  
        fooObj = LoadFooObj(....
    }

    . . .
}

我可能遗漏了一些潜在有害的东西吗?

谢谢。

【问题讨论】:

  • 这很常见,也可以。不改变参数值的想法可能是针对人们过去编写的 100+ 行方法。如果您只有简短的方法,那将不是问题。

标签: c# coding-style refactoring optional-parameters


【解决方案1】:

如果你觉得它有异味,不如来个简单的重载。

public void Foo(int p1, MyClass fooObj)
{
    . . .
}

public void Foo(int p1)
{
    var fooObj = LoadFooObj(....);
    Foo(p1, fooObj);
}

这样可以清楚每个方法的作用,并且您不会更改调用中的参数。

【讨论】:

  • 是的,您的代码看起来不错,谢谢。关键是我不确定原始代码是否有味道)
  • 唯一的问题是,如果没有选项,很难筛选出我被调用的位置。如果您将它们分开,您可以轻松找到 ide 中的所有引用
  • 如果你想有多个可选参数也很棘手 - 重载的数量急剧增加。
  • 这就是为什么我尝试对具有超过 1-2 个参数的方法使用命名参数调用和/或参数从方法名称中不明显的原因之一。当然,这也有助于避免在对调用编码后签名中的一个/多个参数被替换为(和/或在 Params 参数的情况下,删除离开)类型兼容参数时出现意外参数。事实上,我认为应该有一个需要命名参数的“参数显式”编译器选项(VB 中的“选项显式”)。见:stackoverflow.com/a/31145312/401246
【解决方案2】:

那绝对没问题。事实上,这是一种使参数可选的好方法,而不必将值作为常量烘焙。

您可以使用 null-coalescing 运算符使其更具可读性:

fooObj = fooObj ?? LoadFooObj();

您甚至可以考虑对值类型使用相同的方法:

public void Log(string message, DateTime? timestamp = null)
{
    DateTime actualTimestamp = timestamp ?? DateTime.UtcNow;
    ...
}

这样做的一个缺点是它会阻止 null 被用作“正常”有意义的值 - 考虑在特定情况下您是否会需要它。

【讨论】:

    【解决方案3】:

    我将与 Jon Skeet 完全相反,并说这不好,原因有两个:

    1. 应尽可能将所有变量(包括参数)视为不可变的。仅在确实需要时更改它们的值。这会带来更清晰、更易于理解的代码。
    2. 避免使用可选参数。带有可选参数的方法会立即测试该参数,这是一种明显的代码异味:您有两条通过代码的路线,因此将其设为两个方法。

    您可以重载Foo,但请考虑这些方法的作用:它们可能应该被赋予不同的名称来描述它们执行不同操作的事实。不要依赖 cmets 来解释这一点;用代码本身说清楚。

    【讨论】:

    • 我不明白为什么 (2) 特别适用于可选参数。当然,相同的逻辑适用于任何参数,无论它是否具有默认值?
    • 那么它是否也适用于任何带有布尔参数的方法?我只能有两个名称略有不同的方法。
    • @ArturUdod,绝对应该将此规则应用于布尔参数。
    • @MatthewWatson,你是对的。任何用作测试以通过代码在两条不同路径之间进行选择的参数都是“这里可能需要两种方法”的味道。
    猜你喜欢
    • 2011-07-14
    • 1970-01-01
    • 2015-03-25
    • 1970-01-01
    • 2020-04-17
    • 2014-07-30
    • 2023-02-03
    • 2019-06-06
    • 1970-01-01
    相关资源
    最近更新 更多