1

我有检查数据库中记录的图像名称的方法。如果有这种情况,我会尝试使用记录的路径加载图像。如果没有,我会加载默认图像。

首先,我将整个方法放在一个try-catch块中catch(Exception ex),无论我刚刚返回的异常是什么Error loading image

    if (File.Exists(imgPath + "\\" + imageName))
    {
        try
        { 
            using (var temp = new Bitmap(imgPath + "\\" + imageName))
            {
                pictureBox1.Image = new Bitmap(temp);
            }

            if (pictureBox1.Image.Width > defaultPicBoxWidth)
            {
                pictureBox1.Width = defaultPicBoxWidth;
            }
        }
        catch (Exception ex)
        {
            logger.Error(ex.ToString());
            MessageBox.Show("Error loading image!", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
        }
    }

然后我发现有时我可能在数据库中有一条记录,但由于某种原因该文件可能丢失了,所以我添加了检查:

if (imageName != null && !File.Exists(imgPath + "\\" + imageName))

现在我也需要为这种情况提供适当的信息。我得出的结论是,我可以 - 使用几个try-catch块来处理这些部分或抛出异常并处理调用方法的异常。

我选择了第二个选项,现在整个代码是:

    if (imageName != null && !File.Exists(imgPath + "\\" + imageName))
    {
        throw new FileNotFoundException(); 
    }

    if (File.Exists(imgPath + "\\" + imageName))
    {
        //try
        //{ 
            using (var temp = new Bitmap(imgPath + "\\" + imageName))
            {
                pictureBox1.Image = new Bitmap(temp);
            }

            if (pictureBox1.Image.Width > defaultPicBoxWidth)
            {
                pictureBox1.Width = defaultPicBoxWidth;
            }
        //}
        //catch (Exception ex)
        //{
        //    logger.Error(ex.ToString());
        //    MessageBox.Show("Error loading image!", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
        //}
    }

这就是我调用该方法的地方:

try
                {
                    //The name of the method described above
                    LoadSavedOrDefaultImage(imageInfo, entity.Picture, txtCode.Text, imageLocation);
                }
                catch (FileNotFoundException ex)
                {
                    logger.Error(ex.ToString());
                    MessageBox.Show("Error loading image! The file wasn't found.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                }
                catch (Exception ex)
                {
                    LogErrorAndShowMessage(ex, Resources.ERROR_LOAD);
                }

我更喜欢这个,但我不能确切地说出为什么。一般的问题是 - 这是处理异常的正确方法。try-catch而更具体的——在我的确切情况下,放置积木的更好地方是哪里?对我来说,在方法本身的主体中是有意义的,因为这样我就不需要try-catch在我为我调用该方法的任何地方编写那些块,它以这种方式更加封装。现在还有两个try-catch块,但是如果将来逻辑发生变化,我可能想抛出更多不同的异常,这是将异常处理保留在方法本身而不是在调用它的位置的另一个原因,但另一方面......我想要阅读您的意见。

4

2 回答 2

3
  1. 在回答您的一般问题“处理异常的最佳位置在哪里”时,答案很简单:始终处理最接近引发异常的点

    那是您将拥有处理异常所需的最多信息的地方,它还可以降低代码依赖性。如果让异常冒出太多层级,那么高层代码将不得不知道低层代码的实现细节,这会增加耦合并破坏抽象。

    这给我们带来了另一个重要点:如果您没有足够的信息来处理异常,或者您不知道该怎么做,那么您根本不应该处理异常。相反,你应该让它冒泡,直到它最终到达可以处理它的代码,或者失败,一个显示错误消息和/或写入日志文件和/或将转储发送回开发人员的全局异常处理程序( s) 在优雅地结束应用程序之前。例外不像口袋妖怪;你不应该抓住他们。只抓住那些你知道如何处理的人。(有关全局异常处理的相关阅读。

  2. 针对您的具体问题“我如何处理找不到文件/记录/对象的情况”,答案也相对简单:始终处理异常

    乍一看,检查对象是否存在似乎是个好主意。这似乎是防御性编程,而不是尝试做你知道会失败的事情。我们都知道防御性编程是一种最佳实践。

    所以有什么问题?一个相对微妙的,称为竞争条件。看,仅仅因为您在尝试访问它之前确保该对象存在,该对象仍然可能在您验证它的存在和您尝试访问它的时间之间消失。在伪代码中:

    if (!File.Exists(myFile))
    {
        MessageBox("Sorry buddy, that's a no-go.");
    }
    else
    {
        // Uh-oh! The file got deleted!
        File.Open(myFile);  // fails
    }
    

    现在,当然,您可能对自己说,这听起来非常罕见。在执行两行代码之间,对象真正消失的频率是多少(或者您失去了访问它的能力)?好吧,这实际上并不是那么不可能。考虑文件位于网络驱动器上并且网络电缆突然被拔掉的情况。但即使它非常罕见,这就是为什么它被称为异常:它是一个异常[非常罕见] 条件。

    所以这里正确的解决方案是只处理异常,因为即使你进行防御性编程,你仍然需要处理异常来处理竞争条件。而且我们都知道不必要的代码重复是不好的。

于 2013-03-11T12:49:47.210 回答
1

你的第二个选择进展顺利。如果您的代码中有部分不太可能导致任何异常(如果有的话),那么您不应该在try-catch.
在我看来,只有少数情况下只有“一种方法”来处理异常。重要的是,您必须保护那些可能导致程序故障甚至崩溃的代码部分。
此外,使用多个try-catch-blocks 来捕获不同的异常也很好。有时,您希望对某些例外情况进行平等处理,而不是进一步区分它们。然而在其他情况下,有一些你根本没想到的例外,然后你至少可以找到使用catch(Exception ex) { ... }

也许在MSDN上进行一些查找可以帮助您。

于 2013-03-11T12:45:37.013 回答