为什么不推荐使用 'goto' 语句?
Why this 'goto' statement usage is not recommended?
我们公司正在就是否应该在项目中使用 goto
语句展开激烈争论。我个人认为它为以下需要重试 Web 服务调用的场景增加了清晰度。
const string primaryWebServiceUrl = "https://example.com/Server.asmx";
const string secondaryWebServiceUrl = "https://example2.com/Server.asmx";
using (var ws = new Server())
{
ws.Url = primaryWebServiceUrl;
start:
try
{
wsAction?.Invoke(ws);
}
catch
{
if (ws.Url == secondaryWebServiceUrl)
throw;
ws.Url = secondaryWebServiceUrl;
goto start;
}
}
我认为在这种情况下添加循环会牺牲代码的清晰度,而且我发现仅仅为了具有重试逻辑而引用 Polly 是一种矫枉过正的做法。
编辑:因为每个人都说不建议在这里使用 goto 语句,所以我想详细了解为什么不建议这样做以及它可能产生的不利影响。在我看来,这增加了清晰度,但我可以理解,如果使用不当,goto 语句的展开效果可能是负面的,但在上面提供的示例中,为什么不推荐使用 goto 方法?
goto 在 switch 语句之外的任何地方都被认为是非常糟糕的做法。有很多更好的结构。
您可以将 try/catch 逻辑移动到方法中并循环检查结果(可能是 true/false),然后继续调用该方法 - 而不是使用 goto
https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/goto
这个 link 明确提到切换和退出 深度 嵌套循环。这些情况都不适用于此处。
有效,但不推荐;更可读的实现是这样的
using (var ws = new Server()) {
ws.Url = primaryWebServiceUrl;
// Keep doing ...
while (true) {
try {
wsAction?.Invoke(ws);
// ...until Invoke succeeds
break;
}
catch { //TODO: put expected Exception type here
// Something is very wrong; rethrow the exception and leave the routine
if (ws.Url == secondaryWebServiceUrl)
throw;
ws.Url = secondaryWebServiceUrl;
}
}
}
或者更好(特别是如果我们想要有很多 url)——感谢 Panagiotis Kanavos 的想法:
string[] urls = new string[] {
"https://example.com/Server.asmx",
"https://example2.com/Server.asmx",
"https://example3.com/Server.asmx",
...
"https://example123.com/Server.asmx",
};
using (var ws = new Server()) {
// Try each url from urls...
for (int i = 0; i < urls.Length; ++i) {
try {
ws.Url = urls[i];
wsAction?.Invoke(ws);
// ... until success
break;
}
catch {
// The last url failed; rethrow the error
if (i >= urls.Length - 1)
throw;
}
}
}
我们公司正在就是否应该在项目中使用 goto
语句展开激烈争论。我个人认为它为以下需要重试 Web 服务调用的场景增加了清晰度。
const string primaryWebServiceUrl = "https://example.com/Server.asmx";
const string secondaryWebServiceUrl = "https://example2.com/Server.asmx";
using (var ws = new Server())
{
ws.Url = primaryWebServiceUrl;
start:
try
{
wsAction?.Invoke(ws);
}
catch
{
if (ws.Url == secondaryWebServiceUrl)
throw;
ws.Url = secondaryWebServiceUrl;
goto start;
}
}
我认为在这种情况下添加循环会牺牲代码的清晰度,而且我发现仅仅为了具有重试逻辑而引用 Polly 是一种矫枉过正的做法。
编辑:因为每个人都说不建议在这里使用 goto 语句,所以我想详细了解为什么不建议这样做以及它可能产生的不利影响。在我看来,这增加了清晰度,但我可以理解,如果使用不当,goto 语句的展开效果可能是负面的,但在上面提供的示例中,为什么不推荐使用 goto 方法?
goto 在 switch 语句之外的任何地方都被认为是非常糟糕的做法。有很多更好的结构。
您可以将 try/catch 逻辑移动到方法中并循环检查结果(可能是 true/false),然后继续调用该方法 - 而不是使用 goto
https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/goto
这个 link 明确提到切换和退出 深度 嵌套循环。这些情况都不适用于此处。
有效,但不推荐;更可读的实现是这样的
using (var ws = new Server()) {
ws.Url = primaryWebServiceUrl;
// Keep doing ...
while (true) {
try {
wsAction?.Invoke(ws);
// ...until Invoke succeeds
break;
}
catch { //TODO: put expected Exception type here
// Something is very wrong; rethrow the exception and leave the routine
if (ws.Url == secondaryWebServiceUrl)
throw;
ws.Url = secondaryWebServiceUrl;
}
}
}
或者更好(特别是如果我们想要有很多 url)——感谢 Panagiotis Kanavos 的想法:
string[] urls = new string[] {
"https://example.com/Server.asmx",
"https://example2.com/Server.asmx",
"https://example3.com/Server.asmx",
...
"https://example123.com/Server.asmx",
};
using (var ws = new Server()) {
// Try each url from urls...
for (int i = 0; i < urls.Length; ++i) {
try {
ws.Url = urls[i];
wsAction?.Invoke(ws);
// ... until success
break;
}
catch {
// The last url failed; rethrow the error
if (i >= urls.Length - 1)
throw;
}
}
}