我从来不喜欢 out
和 ref
参数。当我看到它们在运行时,它们给我一种设计有些困惑的感觉。
我认为唯一的异常(exception)是所谓的 TryXXX 模式,它返回一个 bool 值作为函数结果(无论是一切正常还是出现问题)和一个实际结果的输出参数,直到我读到 this article今天,它让我思考是否有更好的模式来实现这种方法。
我认为我们可以有一个返回多个结果的函数(或者如文章所说的元组)
Tuple<Exception,T> TryParseT(object obj)
或接受成功回调函数的函数:
void TryParseT(object obj,Action<T> success)
问题是,从功能设计的角度来看,哪个更好?
更新:
换句话说,我想知道这两个函数中哪个更符合函数式编程原则,为什么?
最优雅的方法是
int Parse(string value)
Tryxxxx 方法仅针对名为性能的实现细节而存在。如果您正在寻求优雅,您可以使用 Parse 方法并通过快速失败来处理任何错误。
您可以改为返回一个元组,但这将在堆上花费额外的分配,因为元组是引用类型。
在性能方面(如果您关心的话)更好的解决方案是键值对。但它隐藏了(如元组)通用数据类型背后的语义,这对于代码清晰度来说并不是最佳选择。与定义元组的第一个 bool 包含失败状态的某种约定相比,发出失败信号的更好方法是定义您自己的数据类型。
struct ParseResult<T>
{
public bool Success { get; private set; }
public T Value { get; private set; }
public ParseResult(T value, bool success):this()
{
Value = value;
Success = success;
}
}
class Program
{
static ParseResult<int> TryParse(string s)
{
int lret = 0;
if (int.TryParse(s, out lret))
{
return new ParseResult<int>(lret, true);
}
else
{
return new ParseResult<int>(lret, false);
}
}
static void Main(string[] args)
{
string test = "1";
var lret = TryParse(test);
if( lret.Success )
{
Console.WriteLine("{0}", lret.Value);
}
}
}
该方法仍然非常有效,并且以分配廉价容器对象为代价节省了 out 参数。