【问题标题】:Method naming depending on returntype方法命名取决于返回类型
【发布时间】:2010-10-27 08:03:45
【问题描述】:

为了避免 Tell-don't-ask,我想将我在调用方法之前询问的 bool 属性组合成一个返回 bool 的新方法。

我尝试遵循这个模式,如果一个方法不能执行它的名字所暗示的动作,它会抛出一个异常。比如SendMail不能发送邮件,就会抛出异常。

我希望这个特定的方法返回一个布尔值来表示成功。并且正在考虑是否应该将名称更改为 TrySendMail 之类的名称,也许查看具有 bool 返回类型的方法签名就足够了?

【问题讨论】:

  • 应该没问题。就我个人而言,我什至不会打扰。 bool 返回类型的存在有点暗示成功/失败。
  • 您可以通过返回某种错误代码 Enum 使其更明确,例如:BlockedBySender、InvalidAddress 等...在这种情况下,Try 将是多余的
  • 如今,使用错误代码作为返回值已不受欢迎。如果函数失败,则抛出强类型异常。如果他想知道这类事情,TryWhatever 模式在这种情况下是不合适的。
  • @Mike:你可能想读这个:blogs.msdn.com/b/oldnewthing/archive/2005/01/14/352949.aspx我不确定你和什么人一起玩,但我认为故意抛出异常是不好的。
  • @Chris Lively:我的理解是,如果 (1) 这样做有意义,(2) 您对条件使用最相关的异常,抛出异常并不是一个坏主意手头,和(3)它有据可查。如果值无效,您不会在属性设置器中抛出异常吗?

标签: c# oop


【解决方案1】:

将方法命名为TrySendMail 似乎是一个不错的方法。但是,与您的整体命名方案一致是最重要的。

【讨论】:

    【解决方案2】:

    整个 TryWhatever 命名模式似乎是来自 Microsoft 的一个相当新的东西,但是这种行为(尝试做某事,如果失败则抛出,如果没有则返回有意义的强类型值)已经存在了很久了。

    理论上,如果方法采用接收结果的 ref 参数并返回布尔值,则应使用 TryWhatever。如果方法失败,则返回 false。如果成功,则将结果存储在 ref 参数中(始终是最后一个参数),并返回 true。

    您可以使用 DateTime.TryParse 方法作为示例。如果该方法与该模式不匹配,则它不是此命名约定的候选对象。

    对我来说,在使用此约定时,一致性是关键。不要让开发人员感到惊讶。我们中的一些人是非常可怕的人!

    【讨论】:

    • 我认为这是一个有点不同的“模式”:原始方法似乎没有返回任何东西。它是一个 Action,而不仅仅是一个 Func
    • @Ammitai:我认为 Mike 指的是 TryParse 模式,您通过引用传递参数。
    【解决方案3】:

    如您所知,TrySomething 模式在多个 .NET BCL 方法(各种 TryParse 方法)中使用,人们已经习惯了它,所以它不应该让任何人感到惊讶。

    如果您的方法的签名只是bool TrySendMail(Mail mail),那么发生的事情应该很明显。而且我更愿意看到该签名,而不是:

    bool WasMailSentSuccessfully(Mail mail);
    

    因为从后一种方法看不太清楚该方法是实际发送邮件。因此,就我而言,如果您使用 Try 前缀,那么您将做出正确的命名选择。

    另一方面,当我看到 Try 前缀时,我通常希望在参数列表中看到 out 关键字,这将遵循以下约定:

    bool TrySendMail(Mail mail, out string error);
    

    并用作:

    string error = null;
    if (!TrySendMail(mail, out error))
       Console.WriteLine(error);
    

    这种约定虽然很常见,但从 OOP 的角度来看实际上是相当丑陋的。它基本上是一个返回两个值的方法,而不是通过引用传递一个参数,正确的 OOP 方法是将所有返回值包装在一个新类中。

    所以我更喜欢这样的东西:

    SendResult SendMail(Mail mail);
    

    然后你可以这样使用它:

    SendResult sendResult = SendMail(mail);
    if (!sendResult.Success)
        Console.WriteLine(sendResult.Value);
    

    其中 SendResult 可能类似于:

    public class SendResult : ActionResult<string>
    { ... }
    
    public class ActionResult<T>
    {
        public bool Success { get; private set; }
        public T Value { get; private set; }
        public ActionResult<T>(bool success, T value)
        {
            Success = success;
            Value = value;
        }
    }
    

    好处是以后添加一堆额外的返回值不会改变你的方法的签名。

    【讨论】:

      【解决方案4】:

      我记得在Code Complete 2 中读过一篇关于命名约定的文章(虽然我不记得具体在哪里),除了尝试保持它们通用以便它们可以用于多个应用程序之外,它们都应该具有一定的一致性。在这种情况下,将其称为“SendMail”可以直截了当,让您可以轻松地重用它,而无需用户担心实现细节,它的作用是显而易见的。

      将返回类型设置为布尔值应该明确表明该方法适用于成功/失败操作,从而使“尝试”部分变得多余。

      private bool SendMail()
         {
             try
             {
               //Send mail
               return true;
             } 
             catch()
             {
                //Handle exception
             }
             return false;
          }
      

      如果您要为该方法添加 XML 标头,您甚至可以添加一个说明,说明当您尝试通过 IntelliSense 调用该方法时该方法的作用。

      【讨论】:

        【解决方案5】:

        小心例外。例如,如果传递给 SendMail 的地址格式错误,我认为抛出异常是不合适的。例外是针对异常行为,在我看来,因为地址格式错误而不发送邮件是预期的行为,而不是例外。如果未发送邮件而不是抛出异常,我肯定会返回错误(可能是字符串原因)。抛出异常不仅速度慢,而且意味着堆栈会被展开,因此必须担心让所有内容都处于良好状态。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2023-01-11
          • 1970-01-01
          • 1970-01-01
          • 2021-07-18
          • 1970-01-01
          • 2022-01-09
          • 2020-06-02
          • 2022-11-17
          相关资源
          最近更新 更多