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

时间:2010-03-03 23:20:47

标签: c# python exception try-catch

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

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<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无关。怎么办?

由于

10 个答案:

答案 0 :(得分:9)

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

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

bool success;

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

if (success)
{
    bar();
}

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

答案 1 :(得分:7)

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

我觉得很脏。

答案 2 :(得分:3)

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

这样的东西
try 
{ 
...
} 
catch(Exception ex) 
{ 
...
goto Jump_past_tryelse
} 
...//Code to execute if the try block DID NOT fail

Jump_past_tryelse:
...

答案 3 :(得分:2)

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

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

答案 4 :(得分:2)

只需将放在之前。然后,只有在代码执行到达该点时才会执行:

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的描述中缺少一些重要的内容。

答案 5 :(得分:2)

请允许我从similar StackOverflow question重复一个想法。您无法直接执行此操作,但您可以编写一个封装所需行为的方法。查看原始问题以了解如何实现该方法(如果您不熟悉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 (...);
  });

答案 6 :(得分:1)

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

示例1:(自C#版本7起)

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

如果您更喜欢 lambda语法,,您还可以声明一个运行方法

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

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

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

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

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

DotNetFiddle

中试用

注意:

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

答案 7 :(得分:0)

你可以这样做:

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

答案 8 :(得分:0)

这将是像命中

这样的空语句
try 
{ 
    somethingThatCanThrow(); 
} 
catch(Exception ex) 
{ 
    LogException(ex); 
    return;
} 
ContinueFlow();

答案 9 :(得分:0)

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