这与C#中使用的约定有关。
我有一个有两个参数(X和Y坐标)的方法。这些坐标表示“图块”可以驻留的位置。如果图块位于这些坐标处,则该方法返回其编号。如果这些坐标上没有任何图块,我想知道该方法应该如何表现。
我看到三个选项:
那么,我该怎么办?
答案 0 :(得分:23)
您可以返回null,并在调用代码上检查此内容。
当然你必须使用可以为空的类型:
int? i = YourMethodHere(x, y);
答案 1 :(得分:20)
返回-1。
这不仅仅是一个C ++约定,它在.NET Framework中也很常见 - 例如String.IndexOf之类的方法或者像SelectedIndex这样的属性,用于表示列表的控件。
修改强>
只是详细说明你问题中的三个选项(异常,返回-1,输出参数),返回-1是要走的路。例外情况适用于特殊情况,Microsoft编码指南建议尽可能避免使用参数。
在我的视图中返回-1(假设它总是一个无效的值),返回一个可空的int或返回一个Tile对象都是可接受的解决方案,你应该选择与你应用程序的其余部分最一致的那个。我无法想象任何开发人员都会遇到以下任何一点困难:
int tileNumber = GetTile(x,y);
if (tileNumber != -1)
{
... use tileNumber ...
}
int? result = GetTile(x,y);
if (result.HasValue)
{
int tileNumber = result.Value;
... use tileNumber ...
}
Tile tile = GetTile(x,y);
if (tile != null)
{
... use tile ...
}
我不确定我是否理解Peter Ruderman关于使用int“比返回可空类型更有效”的评论。我认为任何差异都可以忽略不计。
答案 2 :(得分:17)
例外情况属于特殊情况,因此在已知和预期错误情况下使用例外情况“不好”。现在,您更有可能在任何地方尝试捕获以处理此错误,因为您预计会出现此错误情况。
如果您的唯一错误条件(比如-1)与实际值混淆,则可以接受返回值作为参数。如果你有一个负片数,那么这是一个更好的方法。
可以为空的int是参考参数的一种可能的替代方法,但是您正在创建具有此参数的对象,因此如果“错误”是常规的,那么您可能比参考参数更多地工作。正如罗曼在其他地方的评论中所指出的那样,你会发现C#与VB的问题the nullable type被引入太晚了,因为VB提供了很好的语法糖,就像C#一样。
如果您的图块只能是非负图形,则返回-1是表示错误的可接受且传统的方式。就性能和内存而言,它也是最便宜的。
要考虑的其他事情是自我记录。使用-1和异常是惯例:您必须编写文档以确保开发人员了解它们。使用int?
返回或引用参数可以更好地自我描述,并且不会需要文档,以便开发人员知道如何处理错误情况。当然:)你应该总是写文档,就像你每天应该用牙线一样。
答案 3 :(得分:6)
使用可以为空的返回值。
int? GetTile(int x, int y) {
if (...)
return SomeValue;
else
return null;
}
这是最明智的解决方案。
答案 4 :(得分:3)
如果您的方法可以访问底层的tile对象,则另一种可能性是返回tile对象本身,如果没有这样的tile,则返回null。
答案 5 :(得分:2)
我会使用选项2.你是对的,在这种常见情况下抛出异常可能对性能有害,并且使用out参数并返回true或false是有用的但是很难阅读。
另外,请考虑string.IndexOf()
方法。如果未找到任何内容,则返回-1。我会效仿这个例子。
答案 6 :(得分:2)
您可以返回-1,因为这是一种相当常见的C#方法。但是,实际返回单击的tile可能会更好,如果没有单击tile,则返回对singleton NullTile实例的引用。这样做的好处是,您可以为返回的每个值赋予具体含义,而不仅仅是一个除了数值之外没有内在含义的数字。类型'NullTile'在其含义上非常具体,对其代码的其他读者几乎没有疑问。
答案 7 :(得分:2)
最好的选择是返回一个布尔值或返回null。
e.g。
bool TryGetTile(int x, int y, out int tile);
,或者
int? GetTile(int x, int y);
有几个理由喜欢“TryGetValue”模式。首先,它返回一个布尔值,因此客户端代码非常直接,例如:if(TryGetValue(out someVal)){/ * some code * /}。将此与客户端代码进行比较,客户端代码需要硬编码的标记值比较(-1,0,null,捕获一组特殊异常等)“魔术数字”与这些设计一起快速出现,并将紧耦合分解成为一件苦差事。
如果预期会发出sentinel值,null或exception,那么检查使用哪种机制的文档绝对至关重要。如果文档不存在或无法访问,这是一个常见的场景,那么你必须根据其他证据进行推断,如果你做出了错误的选择,那么你只是为自己设置空引用异常或其他不良缺陷。然而,TryGetValue()模式非常接近自我文档的名称和方法签名。
答案 8 :(得分:1)
我对你提出的问题有自己的看法,但是上面已经说过,我也做了相应的投票。
关于你没有提出的问题,或者至少作为上述所有答案的扩展:我将确保在整个应用程序中保持解决方案类似情况的一致性。换句话说,无论你回答什么,在应用程序中保持相同。
答案 9 :(得分:0)
如果该方法是低级库的一部分,那么您的标准.NET设计可能要求您从方法中抛出异常。
这就是.NET框架通常的工作方式。您的更高级别的来电者应该抓住您的例外。
然而,因为你似乎是从UI线程执行此操作,因为你正在响应UI事件而具有性能影响 - 我执行Jay Riggs已经建议的操作,返回null,并确保调用者检查null返回值
答案 10 :(得分:0)
我把它分成两种方法。有CheckTileExists(x,y)
和GetTile(x,y)
之类的内容。前者返回一个布尔值,表示给定坐标是否有一个图块。第二种方法基本上就是你在原帖中讨论的方法,除非它在给出无效坐标时会抛出异常(因为这表明调用者没有先调用CheckTileExists()
,所以它是合法的例外为了速度,你可能希望这两种方法共享一个缓存,这样如果它们被一个接一个地调用,GetTile()
函数的开销可以忽略不计。不知道你是否已经有一个合适的对象来放置这些方法,或者你是否应该在新类中使用它们两种方法。恕我直言,这种方法的性能损失可以忽略不计,代码清晰度的增加远大于它。
答案 11 :(得分:0)
您是否有可能创建(或可能创建)坐标处引用的Tile
对象?如果是这样,您可以返回对该图块的引用,或者如果给定坐标处没有图块,则返回null
:
public Tile GetTile(int x, int y) {
if (!TileExists(x, y))
return null;
// ... tile lookup here...
}