C#:python try / catch / else块的等价物

在Python中,有一个有用的exception处理代码:

try: # Code that could raise an exception except Exception: # Exception handling else: # Code to execute if the try block DID NOT fail 

我认为能够将可能引发的代码与普通代码分开是很有用的。 在Python中,这可能如上所示,但是我在C#中找不到类似的东西。

假设该特征或类似特征不存在,将标准代码放入try块或catch块之后是标准做法吗?

我问的原因是因为我有以下代码:

 if (!IsReadOnly) { T newobj; try { newobj = DataPortal.Update(this); List keys = new List(BasicProperties.Keys); foreach (string key in keys) { BasicProperties[key] = newobj.BasicProperties[key]; } } catch (DataPortalException) { // TODO: Implement DataPortal.Update() recovery mechanism } } 

这需要普通代码在try块中,否则如果引发exception并随后处理,则newobj将被取消分配,但是在try块中有如此多的代码并且与DataPortalException无关,这感觉非常不自然。 该怎么办?

谢谢

我更希望看到try / catch之外的其余代码,因此很清楚你试图捕获的exception来自哪里,并且你不会意外地捕获你不想捕获的exception。

我认为与Python try / catch / else最接近的是使用本地布尔变量来记住是否抛出了exception。

 bool success; try { foo(); success = true; } catch (MyException) { recover(); success = false; } if (success) { bar(); } 

但是,如果你这样做,我会问你为什么不从exception中完全恢复,以便你可以继续,好像已经成功,或者通过返回错误代码完全中止,甚至只是让exception传播给来电者。

野蛮的解决方案:创建一个从Exception派生的Else类,在try块的末尾抛出它的一个实例,并使用catch (Else) {...}来处理其他东西。

我觉得很脏

这可能会被投票,但c#不会转到(注意我几乎没有c#知识,所以我不知道这是否有效)。

什么类似的东西

 try { ... } catch(Exception ex) { ... goto Jump_past_tryelse } ...//Code to execute if the try block DID NOT fail Jump_past_tryelse: ... 

C#没有这样的概念,所以你只剩下三个选项,

  • 把else代码放在try中。
  • 将else代码放在try catch块之外,使用局部变量来表示成功或失败,并在else代码周围使用if块。
  • 将else代码放在finally块中,使用局部变量来指示成功或失败,并使用if块来代替其他代码。

请允许我从类似的StackOverflow问题重复一个想法。 您无法直接执行此操作,但您可以编写一个封装所需行为的方法。 查看原始问题以了解如何实现该方法(如果您不熟悉lambda表达式和Func委托)。 用法可能如下所示:

 TryExceptRaise(() => { // code that can throw exception }, (Exception e) => { // code to run in case of an exception return (...); }, () => { // code to run if there is no exception return (...); }); 

只需将你的“其他”块放在捕获之前 。 然后,只有在代码执行到达该点时才会执行:

 try { fee(); fi(); foe(); fum(); /// put your "else" stuff here. /// It will only be executed if fee-fi-foe-fum did not fail. } catch(Exception e) { // handle exception } 

鉴于此,我没有看到使用try..catch …… else除非OP的描述中缺少重要的东西。

使用C#版本7,您可以使用本地函数来模拟此行为:

示例1 🙁自C#版本7开始)

 void Main() { void checkedCode() { try { foo(); } catch (Exception ex) { recover(); return; } // ElseCode here } checkedCode(); } 

如果您更喜欢lambda语法,还可以声明run方法

 void Run(Action r) { r(); } 

只需要在代码中存在一次,然后使用模式进行匿名方法,如下所示

示例2 🙁较旧的C#版本和C#版本7)

 Run(() => { try { foo(); } catch (Exception) { recover(); return; } // ElseCode here }); 

您需要在安全的上下文中包含代码。

DotNetFiddle中尝试一下


笔记:

  • 在这两个示例中,都创建了一个函数上下文,以便我们可以使用return; 退出时出错。
  • 您可以在JavaScript中找到与示例2中使用的模式类似的模式: 自调用匿名函数 (例如,JQuery使用它们)。 因为在C#中你无法自行调用,所以使用了辅助方法Run
  • 由于Run不必是本地函数,因此示例2也适用于较旧的C#版本

你可以这样做:

 if (!IsReadOnly) { T newobj = null; try { newobj = DataPortal.Update(this); } catch (DataPortalException) { // TODO: Implement DataPortal.Update() recovery mechanism } if (newobj != null) { List keys = new List(BasicProperties.Keys); foreach (string key in keys) { BasicProperties[key] = newobj.BasicProperties[key]; } } } 

这将是像命中一样的空语句

 try { somethingThatCanThrow(); } catch(Exception ex) { LogException(ex); return; } ContinueFlow(); 
 if (!IsReadOnly) { T newobj; bool Done; try { newobj = DataPortal.Update(this); List keys = new List(BasicProperties.Keys); foreach (string key in keys) { BasicProperties[key] = newobj.BasicProperties[key]; } Done = true; } catch (DataPortalException) { // TODO: Implement DataPortal.Update() recovery mechanism Done = false; } finally { if (newobj != null && Done == false) { List keys = new List(BasicProperties.Keys); foreach (string key in keys) { BasicProperties[key] = newobj.BasicProperties[key]; } } } }