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 总是会被调用。

普遍的问题是:

  1. 双重 defer 代码难以阅读
  2. 可能的解决方案总是返回 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)
  }
}                                                                                                               

问题

  1. 我重复了 this.itms.Remove(dump);this.errCnt = 0 这段代码 → 不好
  2. 代码的可读性很差 → 不好

更多关于Golang中从C#转换代码时遇到的问题的实战教程也可以访问 https://www.itying.com/category-94-b0.html

4 回复

重写你所调用的函数,使其返回错误而非引发恐慌。这才是 Go 语言的方式。

更多关于Golang中从C#转换代码时遇到的问题的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


也许吧,但这就是在 Go 中处理它的方式。

如果你坚持要使用 panicrecover 来实现,你需要将每个“恢复点”提取到它自己的函数中。

这将产生大量的样板代码。仅举一个例子:我的错误处理代码将从现在的约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模拟)会跳过外层的清理逻辑,只有成功执行或外层捕获异常时才执行清理。

回到顶部