【问题标题】:C# How to handle multiple exceptions which does all the same?C#如何处理多个相同的异常?
【发布时间】:2010-12-14 23:04:03
【问题描述】:

在我的代码中,我有一个包含多个 catch 语句的方法,它们执行所有相同的语句。我不确定这是实现这一点的正确方法。你会怎么做?

public void LoadControl(ControlDestination controlDestination, string filename, object parameter)
{
    try
    {
        // Get filename with extension
        string file = GetControlFileName(filename);

        // Check file exists
        if (!File.Exists(file))
            throw new FileNotFoundException();

        // Load control from file
        Control control = LoadControl(filename);

        // Check control extends BaseForm
        if (control is BaseForm)
        {
            // Set current application on user control
            ((BaseForm)control).CurrentApplication = this;
            ((BaseForm)control).Parameter = parameter;

            // Set web user control id
            control.ID = filename;

            Panel currentPanel = null;

            switch (controlDestination)
            {
                case ControlDestination.Base:
                    // Set current panel to Base Content
                    currentPanel = pnlBaseContent;
                    // Set control in viewstate
                    this.BaseControl = filename;
                    break;
                case ControlDestination.Menu:
                    // Set current panel to Menu Content
                    currentPanel = pnlMenuContent;
                    // Set control in ViewState
                    this.MenuBaseControl = filename;
                    break;
            }

            currentPanel.Controls.Clear();
            currentPanel.Controls.Add(control);
            UpdateMenuBasePanel();
            UpdateBasePanel();

        }
        else
        {
            throw new IncorrectInheritanceException();
        }
    }
    catch (FileNotFoundException e)
    {
        HandleException(e);
    }
    catch (ArgumentNullException e)
    {
        HandleException(e);
    }
    catch (HttpException e)
    {
        HandleException(e);
    }
    catch (IncorrectInheritanceException e)
    {
        HandleException(e);
    }

}

这就是 HandleException 的样子:

private void HandleException(Exception exception)
{
    // Load error control which shows big red cross
    LoadControl(ControlDestination.Menu, "~/Controls/Error.ascx", null);

    // Store error in database
    DHS.Core.DhsLogDatabase.WriteError(exception.ToString());

    // Show error in errorbox on master
    Master.ShowAjaxError(this, new CommandEventArgs("ajaxError", exception.ToString()));
}

【问题讨论】:

  • 不要捕获 ArgumentNullException,避免它!
  • 我认为这是我选择这样做的方式 - 是的,它有点啰嗦,但你明确说明你在做什么,它允许你采取额外的适当步骤每种情况

标签: c# asp.net .net exception


【解决方案1】:

你做得对(你应该只捕获你要处理的异常,并且没有办法在一个 catch 块中捕获多个异常类型),但作为替代方案,你可以只 @ 987654322@,检查异常类型,如果不是您所期望的,请再次throw,如下所示:

var exceptionTypes=new Type[] {
    typeof(FileNotFoundException),
    typeof(ArgumentNullException),
    //...add other types here
};

catch(Exception ex) {
    if(exceptionTypes.Contains(ex.GetType()) {
        HandleException(ex);
    } else {
        throw;
    }
}

更新:使用 C# 6(与 Visual Studio 2015 一起提供),您可以执行以下操作:

catch(Exception ex) when (exceptionTypes.Contains(ex.GetType()) {
    HandleException(ex);
}

【讨论】:

  • 您应该使用exceptionTypes.Any(type => type.IsAssignableFrom(ex)) 而不是简单的相等比较。
  • 你是对的,与此更改一样,派生异常也会被捕获。
  • 应该是 exceptionTypes.Any(type => type.IsAssignableFrom(ex.getType()))
【解决方案2】:

只要您不介意使用 Lambda,就可以使用泛型来获得更好的解决方案。我不喜欢打开类型。我已经使用过这段代码几次,我发现它对于您希望以相同方式处理许多异常的服务代理特别方便。如上所述,它总是最好在可能的情况下捕获正确类型的异常。

代码通过将异常指定为句柄函数的泛型类型参数来工作。然后捕获这些特定类型,但将其作为基类传递给通用处理程序。我没有添加 HandleAndThrow 但这可以根据需要添加。还可以根据自己的喜好更改命名。

    public static void Handle<T>(Action action, Action<T> handler)
        where T : Exception
    {
        try
        {
            action();
        }
        catch (T exception)
        {
            handler(exception);
        }
    }

    public static void Handle<T1, T2>(Action action, Action<Exception> handler)
        where T1 : Exception
        where T2 : Exception
    {
        try
        {
            action();
        }
        catch (T1 exception)
        {
            handler(exception);
        }
        catch (T2 exception)
        {
            handler(exception);
        }
    }

    public static void Handle<T1, T2, T3>(Action action, Action<Exception> handler)
        where T1 : Exception
        where T2 : Exception
        where T3 : Exception
    {
        try
        {
            action();
        }
        catch (T1 exception)
        {
            handler(exception);
        }
        catch (T2 exception)
        {
            handler(exception);
        }
        catch (T3 exception)
        {
            handler(exception);
        }
    }

    public static void Handle<T1, T2, T3, T4>(Action action, Action<Exception> handler)
        where T1 : Exception
        where T2 : Exception
        where T3 : Exception
        where T4 : Exception
    {
        try
        {
            action();
        }
        catch (T1 exception)
        {
            handler(exception);
        }
        catch (T2 exception)
        {
            handler(exception);
        }
        catch (T3 exception)
        {
            handler(exception);
        }
        catch (T4 exception)
        {
            handler(exception);
        }
    }
}

public class Example
{
    public void LoadControl()
    {
        Exceptions.Handle<FileNotFoundException, ArgumentNullException, NullReferenceException>(() => LoadControlCore(10), GenericExceptionHandler);   
    }

    private void LoadControlCore(int myArguments)
    {
        //execute method as normal
    }

    public void GenericExceptionHandler(Exception e)
    {
        //do something
        Debug.WriteLine(e.Message);
    }        
}

【讨论】:

    【解决方案3】:

    我会这样做

    public void LoadControl(ControlDestination controlDestination, string filename, object parameter)
    {
        try
        {
            // Get filename with extension
            string file = GetControlFileName(filename);
    
            // Check file exists
            if (!File.Exists(file))
                throw new FileNotFoundException();
    
            // Load control from file
            Control control = LoadControl(filename);
    
            // Check control extends BaseForm
            if (control is BaseForm)
            {
                // Set current application on user control
                ((BaseForm)control).CurrentApplication = this;
                ((BaseForm)control).Parameter = parameter;
    
                // Set web user control id
                control.ID = filename;
    
                Panel currentPanel = null;
    
                switch (controlDestination)
                {
                    case ControlDestination.Base:
                        // Set current panel to Base Content
                        currentPanel = pnlBaseContent;
                        // Set control in viewstate
                        this.BaseControl = filename;
                        break;
                    case ControlDestination.Menu:
                        // Set current panel to Menu Content
                        currentPanel = pnlMenuContent;
                        // Set control in ViewState
                        this.MenuBaseControl = filename;
                        break;
                }
    
                currentPanel.Controls.Clear();
                currentPanel.Controls.Add(control);
                UpdateMenuBasePanel();
                UpdateBasePanel();
    
            }
            else
            {
                throw new IncorrectInheritanceException();
            }
        }
        catch (Exception e)
        {
            HandleException(e);
        }
    }
    
    
    public void HandleException(Exception e)
    {
        if (e is FileNotFoundException
                || e is ArgumentNullException
                || e is HttpException
                || e is IncorrectInheritanceException)
        {
            // Load error control which shows big red cross
            LoadControl(ControlDestination.Menu, "~/Controls/Error.ascx", null);
    
            // Store error in database
            DHS.Core.DhsLogDatabase.WriteError(exception.ToString());
    
            // Show error in errorbox on master
            Master.ShowAjaxError(this, new CommandEventArgs("ajaxError", exception.ToString()));
        }
    }
    

    【讨论】:

      【解决方案4】:

      我将以与语言无关的方式回答这个问题:

      1.你现在所做的是正确的。它没有错,只是如果你多次这样做可能会变得乏味。

      2. 捕获最普遍的异常形式。简单的

      catch(Exception e)
      {
          ...
      }
      

      3. 也许您只想捕获一些异常,而不捕获所有异常,如果您只执行#2,您会这样做。

      做你在 #2 中所做的,加上修改 HandleException 以仅处理某些类型的异常。这样一来,您只需键入 tem 一次,它仍然比上面更紧凑。

      private void HandleException(Exception e) throws Excpetion
      {
          // Reject some types of exceptions
          if (!((e is FileNotFoundException) ||
              (e is ArgumentNullException) ||
              (e is HttpException ) ||
              (e is IncorrectInheritanceException )))
          {
              throw;
          }
      
          //Rest of code
          ...
      }
      

      编辑:

      我看到 Konamiman 有第三个选项的improved version。我说去吧。

      【讨论】:

        【解决方案5】:

        我会重构如下:-

        public class Sample
        {
            public void LoadControl( ControlDestination controlDestination, string filename, object parameter )
            {
                HandleExceptions( HandleException, () =>
                {
                    //.... your code
                } );
            }
        
            private void HandleExceptions( Action<Exception> handler, Action code )
            {
                try
                {
                    code();
                }
                catch ( FileNotFoundException e )
                {
                    handler( e );
                }
                catch ( ArgumentNullException e )
                {
                    handler( e );
                }
                catch ( HttpException e )
                {
                    handler( e );
                }
                catch ( IncorrectInheritanceException e )
                {
                    handler( e );
                }
            }
        
            private void HandleException( Exception exception )
            {
                // ....
            }
        }
        

        如果我使用的是 VB.NET,我会使用异常过滤器来进行一系列捕获。但是由于我们使用的是 C#,因此您使用的方法可能是最有效的方法,而不是这样做

        private void HandleExceptions( Action<Exception> handler, Action code )
            {
                try
                {
                    code();
                }
                catch ( Exception e )
                {
                    if ( e is FileNotFoundException
                        || e is ArgumentNullException
                        || e is HttpException
                        || e is IncorrectInheritanceException )
                        handler( e );
                    else
                        throw;
                }
            }
        

        【讨论】:

        • @AZ:嘿,不管你怎么打开:P
        【解决方案6】:

        这样写:

        try
        {
          // code that throws all sorts of exceptions
        }
        catch(Exception e)
        {
          HandleException(e);
        }
        

        编辑:请注意,这是对您问题的直接回答,而不是对这是否是推荐做法的评论。

        edit2:但是,如果e 的类型是特定的异常列表,您可以在函数中进行测试,如果不是,您可以重新抛出它。异常处理性能不是问题,因为它本来就是……异常的。

        【讨论】:

        • 所以,应该是:if (!HandleException(e)) throw;
        猜你喜欢
        • 2018-01-23
        • 1970-01-01
        • 2018-11-02
        • 2011-06-05
        • 1970-01-01
        • 2020-01-29
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多