在Python中,有这样有用的异常处理代码:
try:
# Code that could raise an exception
except Exception:
# Exception handling
else:
# Code to execute if the try block DID NOT fail
我认为能够将 could 引发的代码和异常与正常代码分开是很有用的。在 Python 中,这是可能的,如上所示,但是我在 C# 中找不到类似的东西。
假设该功能或类似功能不存在,将普通代码放在
try
块中或 catch
块之后是标准做法吗?
我问的原因是因为我有以下代码:
if (!IsReadOnly)
{
T newobj;
try
{
newobj = DataPortal.Update<T>(this);
List<string> keys = new List<string>(BasicProperties.Keys);
foreach (string key in keys)
{
BasicProperties[key] = newobj.BasicProperties[key];
}
}
catch (DataPortalException)
{
// TODO: Implement DataPortal.Update<T>() recovery mechanism
}
}
这要求普通代码位于 try 块中,否则如果引发异常并随后处理,
newobj
将被取消分配,但是在 try 块中包含这么多与 无关的代码感觉很不自然DataPortalException
。该怎么办?
谢谢
我更愿意看到 try/catch 之外的其余代码,以便清楚您尝试捕获的异常来自何处,并且您不会意外捕获您不想捕获的异常。
我认为与 Python try/catch/else 最接近的等价物是使用本地布尔变量来记住是否抛出异常。
bool success;
try
{
foo();
success = true;
}
catch (MyException)
{
recover();
success = false;
}
if (success)
{
bar();
}
但是如果你这样做,我会问为什么你不完全从异常中恢复,以便你可以像成功一样继续,或者通过返回错误代码甚至只是让异常完全中止传播给调用者。
野蛮的解决方案:创建一个从 Exception 派生的 Else 类,在 try 块的末尾抛出它的一个实例,然后使用
catch (Else) {...}
来处理其他事情。
我感觉好脏。
C#没有这样的概念,所以你只有三个选择,
这可能会被否决,但 c# 没有 goto (注意我几乎没有 c# 知识,所以我不知道这是否有效)。
类似的东西怎么样
try
{
...
}
catch(Exception ex)
{
...
goto Jump_past_tryelse
}
...//Code to execute if the try block DID NOT fail
Jump_past_tryelse:
...
请允许我重复一下类似的 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 (...);
});
只需将“else”块放在之前捕获即可。然后,只有当代码执行到达该点时,它才会执行:
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
});
无论您需要将代码封装在安全上下文中。
using System;
public class Program
{
public static void Main()
{
var objDemo = new Demo();
objDemo.runWithException = false;
objDemo.Example1();
// now the same with exception
objDemo.runWithException = true;
objDemo.Example1();
Console.WriteLine();
objDemo.runWithException = false;
objDemo.Example2();
// now the same with exception
objDemo.runWithException = true;
objDemo.Example2();
}
}
public class Demo
{
public bool runWithException { get; set; } = false;
public void Example1()
{
void checkedCode()
{
try
{
foo();
}
catch (Exception)
{
recover();
return;
}
// ElseCode here
Console.WriteLine("Hello from else");
}
checkedCode();
}
void Run(Action r) { r(); }
public void Example2()
{
Run(() =>
{
try
{
foo();
}
catch (Exception)
{
recover();
return;
}
// ElseCode here
Console.WriteLine("Hello from else");
});
}
public void foo()
{
Console.WriteLine("Hello from foo()");
if (this.runWithException) throw new ApplicationException("TestException");
}
public void recover()
{
Console.WriteLine("Hello from recover()");
}
}
备注:
你可以这样做:
if (!IsReadOnly)
{
T newobj = null;
try
{
newobj = DataPortal.Update<T>(this);
}
catch (DataPortalException)
{
// TODO: Implement DataPortal.Update<T>() recovery mechanism
}
if (newobj != null)
{
List<string> keys = new List<string>(BasicProperties.Keys);
foreach (string key in keys)
{
BasicProperties[key] = newobj.BasicProperties[key];
}
}
}
这将是像 hits 这样的空语句
try
{
somethingThatCanThrow();
}
catch(Exception ex)
{
LogException(ex);
return;
}
ContinueFlow();
if (!IsReadOnly)
{
T newobj;
bool Done;
try
{
newobj = DataPortal.Update<T>(this);
List<string> keys = new List<string>(BasicProperties.Keys);
foreach (string key in keys)
{
BasicProperties[key] = newobj.BasicProperties[key];
}
Done = true;
}
catch (DataPortalException)
{
// TODO: Implement DataPortal.Update<T>() recovery mechanism
Done = false;
}
finally
{
if (newobj != null && Done == false)
{
List<string> keys = new List<string>(BasicProperties.Keys);
foreach (string key in keys)
{
BasicProperties[key] = newobj.BasicProperties[key];
}
}
}
}