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

C#:相当于python的try/catch/else块,c#,python,exception,try-catch,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#中找不到类似的东西 假设功能或类似功能不存在,将普

在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
    }
}
如果(!IsReadOnly)
{
T newobj;
尝试
{
newobj=DataPortal.Update(这个);
列表键=新列表(BasicProperties.keys);
foreach(字符串键入键)
{
基本属性[键]=新对象基本属性[键];
}
}
捕获(DataPortalException)
{
//TODO:实现DataPortal.Update()恢复机制
}
}
这要求正常代码位于try块中,因为否则,如果引发异常并随后进行处理,
newobj
将被取消分配,但是在try块中有这么多与
DataPortalException
无关的代码感觉很不自然。怎么办


谢谢

您可以这样做:

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];
        }
    }
}
如果(!IsReadOnly)
{
T newobj=null;
尝试
{
newobj=DataPortal.Update(这个);
}
捕获(DataPortalException)
{
//TODO:实现DataPortal.Update()恢复机制
}
if(newobj!=null)
{
列表键=新列表(BasicProperties.keys);
foreach(字符串键入键)
{
基本属性[键]=新对象基本属性[键];
}
}
}

那将是像hits一样的空语句

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

我更希望看到try/catch之外的其余代码,这样就可以清楚地知道您试图捕获的异常来自何处,并且不会意外捕获到您不想捕获的异常

我认为与pythontry/catch/else最接近的等效方法是使用一个局部布尔变量来记住是否引发了异常

bool success;

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

if (success)
{
    bar();
}
但是如果你这样做的话,我会问你为什么不从异常中完全恢复,这样你就可以像成功一样继续,或者通过返回错误代码或者甚至让异常传播到调用方来完全中止。

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

  • 将else代码放在try中
  • 将else代码置于try-catch块之外,使用局部变量指示成功或失败,并在else代码周围使用if块
  • 将else代码放在finally块中,使用局部变量表示成功或失败,并在else代码周围使用if块
只要把你的“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的描述中缺少了一些重要的东西。

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

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 (...);
  });

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


我觉得自己很脏。

这可能会被否决,但c#have goto(注意,我几乎没有c#knowledge,所以我不知道这是否有效)

像这样的怎么样

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

Jump_past_tryelse:
...
如果(!IsReadOnly)
{
T newobj;
布尔多;
尝试
{
newobj=DataPortal.Update(这个);
列表键=新列表(BasicProperties.keys);
foreach(字符串键入键)
{
基本属性[键]=新对象基本属性[键];
}
完成=正确;
}
捕获(DataPortalException)
{
//TODO:实现DataPortal.Update()恢复机制
完成=错误;
}
最后
{
if(newobj!=null&&Done==false)
{
列表键=新列表(BasicProperties.keys);
foreach(字符串键入键)
{
基本属性[键]=新对象基本属性[键];
}
}
}
}
对于C#version 7,您可以使用本地函数来模拟此行为:

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

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

void Run(Action r) { r(); }
它只需要在代码中出现一次,然后对匿名方法使用如下模式

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

您需要在安全上下文中包含代码的任何地方


注意事项:

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

因此,我一直不喜欢使用try-catch块。没有办法区分“是否破译代码”和“是否破译代码”。投票以完全相同的方式结束:这可能会
void Main()
{
    void checkedCode()
    {
        try 
        {
            foo();
        }
        catch (Exception ex)
        {
            recover();
            return;
        }
        // ElseCode here
    }
    checkedCode();
}
void Run(Action r) { r(); }
Run(() => {
    try
    {
        foo();
    }
    catch (Exception)
    {
        recover();
        return;
    }
    // ElseCode here
});