【问题标题】:Return code or out parameter?返回码还是输出参数?
【发布时间】:2011-04-10 17:18:08
【问题描述】:

我正在制作一种从服务器获取文件名列表的方法,但我遇到了一个我无法回答的问题。

该方法返回两件事:

  • SftpResult,它是一个具有多种返回码的枚举。
  • 文件名列表。

在这三个签名中:

public static ArrayList GetFileList(string directory, out SftpResult result)

public static SftpResult GetFileList(string directory, out ArrayList fileNames)

public static SftpFileListResult GetFileList(string directory)

(其中SftpFileListResultSftpResultArrayList 的复合对象)

哪个是首选,为什么?

【问题讨论】:

  • SftpResult 的目的是什么?如果它应该解释调用失败的原因,也许你应该抛出一个异常。
  • 考虑到我所做的只是报告状态,我认为这太过分了。如果它失败,这不是一个严重的问题,而且我真的不需要仅仅因为他们输入了错误的目录而展开堆栈。我只是返回一个 DirectoryNotFound 并继续我的业务 :-)
  • 考虑放弃使用 ArrayList 转而使用 IEnumerable
  • 谢谢 Eric,我现在正在尝试这样做。有没有更短的写法:return new ReadOnlyCollection<string>((List<string>)(IEnumerable<string>)Connection.SshConnection.GetFileList(directory));?? Connection.SshConnection.GetFileList(directory) 部分返回 ArrayList
  • @rmx Enumerable.Cast 和 List.AsReadOnly 可以在这里提供帮助 return ...GetFileList(directory).Cast<string>().ToList().AsReadOnly();

标签: c# pass-by-reference


【解决方案1】:

我个人更喜欢最后一个选项(尽管使用List<T>ReadOnlyCollection<T> 而不是ArrayList)。 out 参数基本上是一种返回多个值的方式,一般最好将它们封装起来。

.NET 4 中的另一个选项是

Tuple<SftpResult, ArrayList> GetFileList(string directory)

这明确地说,“这个方法返回两个东西......我已经为你把它们打包在一起,但不值得进一步封装它们:它们不值得组合成一个单独的类型”。

(如果您不使用 .NET 4,您始终可以编写自己的 Tuple 类型。)

【讨论】:

  • 谢谢,我什至没有考虑元组。这是我对第三种选择的主要问题:我觉得它并不能真正保证一个全新的课程。
  • +1 也适用于元组,这可能是我最喜欢的 .NET 4 之一。
  • 数不清这些年来我创建了多少自定义元组类 - 很高兴终于有了一个真正的元组!现在,如果我只能让我们的项目从 3.4 更新到 4...
  • 伙计,我想要元组。 :( 以前从未使用过,但它看起来很有用。
【解决方案2】:

我更愿意将它包装在一个返回对象中:

class FileResult
{
    public FileResult(SftpResult resultCode, IEnumerable<string> files)
    {
         ResultCode = resultCode;
         FileList = new List<string>(files);
    }
    public SftpResult ResultCode { get; private set; }
    public IEnumerable<string> FileList { get; private set; }
}

不用out感觉干净多了。

【讨论】:

  • 我认为这是最后一个选项......虽然我个人认为它是不可变的。
  • @Jon:是的,这是最后一个选项,当然它应该是不可变的。我不知道我怎么了;今天不应该在这里;)
【解决方案3】:

我更喜欢最后一个选项。 Out 参数很少使用,可能会让一些人感到惊讶/困惑。创建复合结果对象是一个干净的解决方案。唯一的缺点是您必须专门为此目的创建一个类。

【讨论】:

  • ".. 很少使用,可能会令人惊讶.." - 尝试告诉 C 或 C++ 程序员!
【解决方案4】:

我会说第三个,因为它将您需要的逻辑封装在一个位置。我只能假设 SftpResult 和 ArrayList 返回方法应该是私有的,然后组成复合返回对象的内部逻辑。

【讨论】:

    【解决方案5】:

    我会成功的:

    public static bool GetFileList(string directory, out SftpResult result, out ArrayList fileNames)
    

    所以对于函数的作用没有混淆,如果 GetFileList 失败,我也会返回一个布尔值。

    【讨论】:

      【解决方案6】:

      如果你喜欢一个函数做两件事的设计,那么我会使用一个 la Jon 的元组或一个 la Fredrik 的返回对象。

      如果您想完全了解它,您可以让类型系统完成工作:

      abstract class FtpResult { ... }
      sealed class FileList : FtpResult { ... }
      sealed class Error : FtpResult { ... }
      ...
      sealed class FtpService
      {
          ...
          public FtpResult GetFileList(string directory) { ... }
          ...
      }
      ...
      var result = service.GetFileList(dir);
      var error = result as Error;
      var list = result as FileList;
      if (error != null) { ... }
      else if (list != null)
      {
          foreach(var name in list.Files) { ... }
      }
      ... 
      

      【讨论】:

        【解决方案7】:

        为什么不提供全部三个?我更喜欢在我的函数调用中没有参数,但我可以理解很多时候需要它们。如果您不知道要支持哪个签名,则支持所有三个。最终,选择权在呼叫者一方,您能做的最好的事情就是提供这个选择。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2021-12-18
          • 2012-06-28
          • 1970-01-01
          • 1970-01-01
          • 2012-08-06
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多