假设我有一个需要返回一些整数值的函数。但它也可能失败,我需要知道它何时发生。
哪种方式更好?
public int? DoSomethingWonderful()
或
public bool DoSomethingWonderful(out int parameter)
这可能更像是一个风格问题,但我仍然很好奇人们会采取哪种选择。
编辑:澄清,这段代码与一个黑盒子对话(我们称之为云。不,黑盒子。不,等等。云。是的)。我不在乎为什么它失败了。我只需要知道我是否有有效值。
答案 0 :(得分:12)
我更喜欢可以为空的版本,因为你可以使用null coalesce operator?在它上面,例如:
int reallyTerrible = 0;
var mightBeWonderful = DoSomethingWonderful() ?? reallyTerrible;
答案 1 :(得分:5)
这取决于您对调用代码的看法。因此您的函数用于什么。
一般来说,你应该避免争论。另一方面,拥有这样的代码可能会很好:
int parameter;
if (DoSomething(out paramameter))
{
// use parameter
}
当你有一个可以为空的int时,它看起来像这样:
int? result = DoSomething();
if (result != null)
{
// use result
}
这有点好,因为你没有out参数,但决定函数是否成功的代码看起来不是很明显。
不要忘记还有另一种选择:使用Exeptions。只有当你的函数失败的情况真的是一个特殊的错误情况时才这样做。
try
{
// normal case
int result = DoSomething()
}
catch (SomethingFailedException ex)
{
// exceptional case
}
例外的一个优点是你不能忽略它。正常情况也很容易实施。如果您可以忽略特殊情况,则不应使用例外。
编辑:忘记提及:异常的另一个好处是,您还可以提供操作失败原因的信息。此信息由Exception类型,Exception的属性和消息文本提供。
答案 2 :(得分:3)
为什么不抛出异常?
答案 3 :(得分:2)
我会遵循.Net库中某些地方使用的模式,如:
bool int.TryParse(string s, out value)
bool Dictionary.TryGetValue(T1 key, out T2 value)
所以我会说:
public bool TryDoSomethingWonderful(out int parameter)
答案 4 :(得分:2)
我会使用第二个,因为如果调用成功,我可能需要马上知道,在这种情况下我宁愿写
int x;
if( DoSomethingWonderful( out x ) )
{
SomethingElse(x);
}
大于
int? x = DoSomethingWonderful();
if( x.HasValue )
{
SomethingElse(x.Value);
}
答案 5 :(得分:2)
这实际上取决于你在做什么。
null是一个有意义的答案吗?如果没有,我更喜欢bool TryDoSomethingWonderful(out int)
方法调用。这与框架相符。
但是,如果null是一个有意义的返回值,则返回int?有道理。
答案 6 :(得分:2)
除非性能是主要问题,否则应返回int
并在失败时抛出异常。
答案 7 :(得分:1)
我赞成使用输出参数。在我看来,这是一种最适合使用输出参数的情况。
是的,您可以使用coalesce运算符将代码保持为单行代码,当且仅当您具有可在其余代码中使用的替代值时。我经常发现对我来说情况并非如此,而且我宁愿执行与我成功检索值时不同的代码路径。
int value;
if(DoSomethingWonderful(out value))
{
// continue on your merry way
}
else
{
// oops
Log("Unable to do something wonderful");
if (DoSomethingTerrible(out value))
{
// continue on your not-so-merry way
}
else
{
GiveUp();
}
}
此外,如果我想要检索的值实际上是可空的,那么在我看来,使用带有输出参数和布尔返回值的函数是解释“我在检索中失败”之间区别的最简单方法值“和”我检索的值为null“。有时我关心这种区别,例如在下面的例子中:
private int? _Value;
private bool _ValueCanBeUsed = false;
public int? Value
{
get { return this._Value; }
set
{
this._Value = value;
this._ValueCanBeUsed = true;
}
}
public bool DoSomethingTerrible(out int? value)
{
if (this._ValueCanBeUsed)
{
value = this._Value;
// prevent others from using this value until it has been set again
this._ValueCanBeUsed = false;
return true;
}
else
{
value = null;
return false;
}
}
在我看来,大多数人不倾向于使用输出参数的唯一原因是因为他们发现语法很麻烦。但是,我真的觉得使用输出参数是解决这个问题的更合适的方法,我发现一旦习惯了它,我发现语法比返回空值更可取。
答案 8 :(得分:0)
如果只有一种方法可以失败,或者你永远不需要知道为什么它失败了,我会说它可能更简单,更容易使用可空的返回值。< / p>
相反,如果有多种方法可能会失败,并且调用代码可能想要确切地知道它失败的原因,那么请使用out参数并返回错误代码而不是bool(或者,您可以抛出异常,但根据你的问题,似乎你已经决定不抛出异常了。)
答案 9 :(得分:0)
你应该使用try catch。这似乎是调用者不知道会发生什么?
我们应该检查bool和out,或者我应该检查两者都返回null和实际返回。
让方法做它应该做的事情,并且在它失败的情况下,让调用者知道它失败了,并且调用者应该被重新命名。
答案 10 :(得分:0)
有趣的是,根据方法的性质,我的个人观点明显受到影响。具体来说,如果方法的目的是检索单个值,则与“做某事”相反。
例如:
bool GetSerialNumber(out string serialNumber)
VS
string GetSerialNumber() // returns null on failure
第二种感觉对我来说更加“自然”,同样地:
bool GetDeviceId(out int id)
VS
int? GetDeviceId() // returns null on failure`
但我承认这真的属于“编码风格”领域。
哦,我也倾向于抛弃异常抛出:
int GetDeviceId() // throws an exception on read failure
我仍然没有卖掉为什么他们会这么错。奥伦,我们可以有一个主题吗? ; - )
答案 11 :(得分:0)
我不喜欢微软的“尝试”模式,其中“out”参数用于返回数据项。除此之外,以这种方式编码的方法不能用于协变接口。如果可能需要超出true / false的内容,我宁愿看到编码为:T GetValue(out bool Successful)
或者T GetValue(out GetValueErrorEnum result);
或T GetValue(out GetValueErrorInfo result);
的方法。由于每种数据类型都具有合法的默认值,因此在函数失败时决定返回什么是没有问题的。调用代码很容易说:
bool success; var myValue = Thing.GetValue(ref success); if (success) .. do something using myValue else .. ignore myValue
如果.net和C#提供了真正的协变“复制输出”参数(调用者将为结果分配空间,将指向该空间的指针传递给被调用函数,然后将分配的空间复制到传递,那将是很好的。 -in仅在函数返回后才变量。)