C#:相当于 python try/catch/else 块

问题描述 投票:0回答:10

在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
。该怎么办?

谢谢

c# python exception try-catch
10个回答
9
投票

我更愿意看到 try/catch 之外的其余代码,以便清楚您尝试捕获的异常来自何处,并且您不会意外捕获您不想捕获的异常。

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

bool success;

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

if (success)
{
    bar();
}

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


8
投票

野蛮的解决方案:创建一个从 Exception 派生的 Else 类,在 try 块的末尾抛出它的一个实例,然后使用

catch (Else) {...}
来处理其他事情。

我感觉好脏。


3
投票

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

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

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:
...

2
投票

请允许我重复一下类似的 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 (...);
  });

2
投票

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


1
投票

使用 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

尝试一下
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()");
    }

}

备注:

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

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

0
投票

这将是像 hits 这样的空语句

try 
{ 
    somethingThatCanThrow(); 
} 
catch(Exception ex) 
{ 
    LogException(ex); 
    return;
} 
ContinueFlow();

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];
                    }
                }
            }
        }
© www.soinside.com 2019 - 2024. All rights reserved.