Golang中从C#转换代码时遇到的问题
Golang中从C#转换代码时遇到的问题
你好,我有一小段 C# 代码,但在 Go 中实现双重 try..catch 时遇到了问题。
c# 代码:
void IEvent.Event () {
if (itms.Count <= 0) {
ErrorSetCONTINUE();
} else {
MqDumpC dump = itms.Peek();
try {
MqC ftr = SlaveGetFilter();
try {
ProxyForward(ftr, dump);
} catch {
if (++errCnt <= 3) {
ErrorReset();
return;
} else {
throw;
}
}
} catch (Exception ex) {
ErrorCatch (ex);
ErrorWrite();
}
itms.Dequeue();
errCnt = 0;
}
}
go 代码:
func (this *Filter4) Event() {
if (this.itms.Len() <= 0) {
MqErrorSetCONTINUE()
} else {
dump := this.itms.Front()
defer func() {
if x := recover(); x != nil {
this.ErrorCatch(x)
this.ErrorWrite()
}
this.itms.Remove(dump)
this.errCnt = 0
}()
ftr := this.SlaveGetFilter()
defer func() {
if x := recover(); x != nil {
this.errCnt++
if this.errCnt <= 3 {
this.ErrorReset_0()
return;
} else {
panic(x)
}
}
}()
this.ProxyForward(ftr, dump.Value.(*MqDumpC))
}
}
问题在于内部的 try..catch 执行了一个 return。这个 return 会跳过 C# 中的第一个 try...catch。
在 Go 中,我使用两个 defer 来实现双重 try...catch。问题是第一个 defer 总是会被调用。
普遍的问题是:
- 双重
defer代码难以阅读 - 可能的解决方案总是返回
error而不使用panic,但这很难实现,因为作为发送者,你永远不知道接收者是否在使用error。
我希望在 Go 中使用 try...catch 的行为。
谢谢。
+++ 补充 +++ 这是一个可行的解决方案:
func (this *Filter4) proxyForward(ftr *MqC, dump *list.Element) {
defer func() {
if x := recover(); x != nil {
if _,ok := x.(*MqExceptionC); ok {
this.errCnt++
if this.errCnt <= 3 {
this.ErrorReset_0()
return;
} else {
panic(x)
}
} else {
panic(x)
}
}
}()
this.ProxyForward(ftr, dump.Value.(*MqDumpC))
this.itms.Remove(dump)
this.errCnt = 0
}
func (this *Filter4) Event() {
if (this.itms.Len() <= 0) {
MqErrorSetCONTINUE()
} else {
dump := this.itms.Front()
defer func() {
if x := recover(); x != nil {
this.ErrorCatch(x)
this.ErrorWrite()
this.itms.Remove(dump)
this.errCnt = 0
}
}()
ftr := this.SlaveGetFilter()
this.proxyForward(ftr, dump)
}
}
问题
- 我重复了
this.itms.Remove(dump);this.errCnt = 0这段代码 → 不好 - 代码的可读性很差 → 不好
更多关于Golang中从C#转换代码时遇到的问题的实战教程也可以访问 https://www.itying.com/category-94-b0.html
重写你所调用的函数,使其返回错误而非引发恐慌。这才是 Go 语言的方式。
更多关于Golang中从C#转换代码时遇到的问题的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
也许吧,但这就是在 Go 中处理它的方式。
如果你坚持要使用 panic 和 recover 来实现,你需要将每个“恢复点”提取到它自己的函数中。
这将产生大量的样板代码。仅举一个例子:我的错误处理代码将从现在的约100行增加到大约10,000行。每个函数调用都会返回一个error,并且对于每个error返回都需要一个if..语句。
在Go中模拟C#的双重try-catch确实需要特殊处理。以下是更简洁的实现方案:
func (this *Filter4) Event() {
if this.itms.Len() <= 0 {
MqErrorSetCONTINUE()
return
}
dump := this.itms.Front()
ftr := this.SlaveGetFilter()
// 外层recover处理
defer func() {
if x := recover(); x != nil {
this.ErrorCatch(x)
this.ErrorWrite()
this.cleanup(dump)
}
}()
// 内层recover处理
func() {
defer func() {
if x := recover(); x != nil {
this.errCnt++
if this.errCnt <= 3 {
this.ErrorReset_0()
panic(x) // 重新panic让外层捕获
}
panic(x) // 超过3次继续向上传递
}
}()
this.ProxyForward(ftr, dump.Value.(*MqDumpC))
this.cleanup(dump)
}()
}
// 提取公共清理逻辑
func (this *Filter4) cleanup(dump *list.Element) {
this.itms.Remove(dump)
this.errCnt = 0
}
或者使用命名函数进一步简化:
func (this *Filter4) Event() {
if this.itms.Len() <= 0 {
MqErrorSetCONTINUE()
return
}
dump := this.itms.Front()
ftr := this.SlaveGetFilter()
defer this.outerRecover(dump)
this.innerTry(ftr, dump)
}
func (this *Filter4) innerTry(ftr *MqC, dump *list.Element) {
defer func() {
if x := recover(); x != nil {
this.errCnt++
if this.errCnt <= 3 {
this.ErrorReset_0()
panic(x)
}
panic(x)
}
}()
this.ProxyForward(ftr, dump.Value.(*MqDumpC))
this.cleanup(dump)
}
func (this *Filter4) outerRecover(dump *list.Element) {
if x := recover(); x != nil {
this.ErrorCatch(x)
this.ErrorWrite()
this.cleanup(dump)
}
}
func (this *Filter4) cleanup(dump *list.Element) {
this.itms.Remove(dump)
this.errCnt = 0
}
这种结构更接近C#的try-catch语义,内层的return(通过panic/recover模拟)会跳过外层的清理逻辑,只有成功执行或外层捕获异常时才执行清理。

