C# 返回码还是输出参数?

C# 返回码还是输出参数?,c#,pass-by-reference,C#,Pass By Reference,我正在制作一个从服务器获取文件名列表的方法,但遇到了一个无法回答的问题 该方法返回两个结果: 一个SftpResult,它是一个包含各种返回码的枚举 文件名列表 在这三个签名中: publicstaticarraylistgetfilelist(字符串目录,out-SftpResult) public static SftpResult GetFileList(字符串目录,out ArrayList文件名) 公共静态SftpFileListResult GetFileList(字符串目录)

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

该方法返回两个结果:

  • 一个
    SftpResult
    ,它是一个包含各种返回码的枚举
  • 文件名列表
在这三个签名中:

publicstaticarraylistgetfilelist(字符串目录,out-SftpResult)

public static SftpResult GetFileList(字符串目录,out ArrayList文件名)

公共静态SftpFileListResult GetFileList(字符串目录)

(其中
SftpFileListResult
SftpResult
ArrayList
的复合对象)


首选哪一种?为什么?

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

我个人更喜欢最后一个选项(尽管使用
列表
只读集合
而不是
数组列表
out
参数基本上是返回多个值的一种方式,封装这些值通常更好

NET4中的另一个选项是

Tuple<SftpResult, ArrayList> GetFileList(string directory)
Tuple GetFileList(字符串目录)
它明确地说,“这个方法返回两个东西……我已经为您将它们打包在一起用于这个特定的情况,但是不值得进一步封装它们:它们不值得组合成单独的类型”


(如果您不使用.NET 4,您可以随时编写自己的
元组
类型。)

我更愿意将其封装在返回对象中:

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; }
}
class文件结果
{
公共文件结果(SftpResult resultCode,IEnumerable文件)
{
结果代码=结果代码;
FileList=新列表(文件);
}
公共SFTPRESLT结果代码{get;private set;}
公共IEnumerable文件列表{get;private set;}
}

不使用
out

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

我会:

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

因此,对于函数的功能没有任何混淆,如果GetFileList可能失败,我也会返回bool。

为什么不提供这三个呢?我不喜欢在函数调用中使用out参数,但我知道在很多时候它们是需要的。如果您不知道支持哪一个签名,请支持所有三个签名。最终,选择权在调用者一边,你能做的最好的事情就是提供这个选择。

如果你喜欢一个函数做两件事的设计,那么我会使用元组a la Jon或返回对象a 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) { ... }
}
... 

我想这是最后一个选择了。。。虽然我个人认为它是不可变的。@Jon:是的,这是最后一个选项,当然它应该是不可变的。我不知道我怎么了;今天不应该在这里;)谢谢,我甚至没有考虑过元组。这是我对第三个选项的主要问题:我觉得它并不能保证一个全新的类。+1也适用于元组,这可能是我对.NET 4最喜欢的东西之一。我无法计算这些年来我创建了多少自定义元组类-很高兴终于有了一个真正的元组!现在,如果我能让我们的项目从3.4升级到4…伙计,我想要Tuple.:(以前从未使用过一个,但它看起来非常有用。SFTPrust的目的是什么?如果它应该解释调用失败的原因,也许你应该抛出一个异常。考虑到我所做的只是报告状态,我认为这太过分了。如果它失败,这不是一个严重的问题,我真的不需要解开堆栈只是因为他们键入了错误的目录。我只是返回了一个DirectoryNotFound并继续我的业务:-)考虑放弃使用ArrayList,转而使用IEnumerable。谢谢Eric,我现在正在尝试这样做。是否有较短的编写方法:
returnnewreadonlycollection((List)(IEnumerable)Connection.SshConnection.GetFileList(directory))??
Connection.SshConnection.GetFileList(directory)
部分返回一个
ArrayList
@rmx Enumerable.Cast和List.AsReadOnly可以在这里帮助
返回…GetFileList(directory.Cast().ToList().AsReadOnly()“很少使用,也可能令人惊讶”-尝试告诉C或C++程序员!