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]; } } } }