关于使用try catch的适当时机

u010233287 2017-08-02 02:20:53
加精
一直搞不清楚什么时候该用try catch,什么时候不该用。比如下面的代码
public static Stream ToStream(Image image)
{
ImageFormat format = image.RawFormat;
MemoryStream ms = new MemoryStream();
image.Save(ms, format);
return ms;
}

1、我需要捕获image为null然后抛出异常吗?
2、我需要捕获image.Save 然后抛出异常吗?

请各位大神指点迷津!
...全文
4674 36 打赏 收藏 转发到动态 举报
写回复
用AI写文章
36 条回复
切换为时间正序
请发表友善的回复…
发表回复
小伙真帅 2017-11-01
  • 打赏
  • 举报
回复
引用 34 楼 closurer 的回复:
引用 17 楼 arpnet99 的回复:
[quote=引用 1 楼 closurer 的回复:] 我先占个坑,再找时间来写写。
你占了坑,有时间再写也填不了你占的这个位置的坑。
你说得对,逻辑思维能力这么好,一定是个出色的程序员。 [/quote] 就好比我们写 //TODO: XXX未做完,有时间再来整理
xdedzl 2017-10-11
  • 打赏
  • 举报
回复
回帖能得分么?想知道
闭包客 2017-09-14
  • 打赏
  • 举报
回复
引用 17 楼 arpnet99 的回复:
引用 1 楼 closurer 的回复:
我先占个坑,再找时间来写写。
你占了坑,有时间再写也填不了你占的这个位置的坑。
你说得对,逻辑思维能力这么好,一定是个出色的程序员。
闭包客 2017-09-14
  • 打赏
  • 举报
回复
五、 从函数设计的角度上讲,在这个函数内部取 Image 的 RawFormat,我认为并不是很好,就是会发生没有原格式的问题。 https://code.csdn.net/closurer/less-image/tree/master/Less.Image/ImageExtensions.cs 我写的图片缩放模块有一个相似的方法,是把 ImageFormat 作为参数传入的:

        /// <summary>
        /// 保存图片
        /// </summary>
        /// <param name="i"></param>
        /// <param name="format">图像格式</param>
        /// <param name="value">图片质量(1-100)</param>
        /// <returns></returns>
        /// <exception cref="NullReferenceException">Image 不能为 null</exception>
        /// <exception cref="InvalidOperationException">不支持的 ImageFormat</exception>
        /// <exception cref="ExternalException">该图像以错误的图像格式保存</exception>
        public static MemoryStream Save(this System.Drawing.Image i, ImageFormat format, int value)
        {
            MemoryStream stream = new MemoryStream();

            if (i.RawFormat == ImageFormat.Gif)
            {
                using (System.Drawing.Image gif = ImageExtensions.Quantizer.Quantize(i))
                {
                    try
                    {
                        gif.Save(stream, format.ToImageCodecInfo(), value.ToEncoderParameters());
                    }
                    catch (ArgumentNullException)
                    {
                        throw new InvalidOperationException("不支持的 ImageFormat");
                    }
                }
            }
            else
            {
                try
                {
                    i.Save(stream, format.ToImageCodecInfo(), value.ToEncoderParameters());
                }
                catch (ArgumentNullException)
                {
                    throw new InvalidOperationException("不支持的 ImageFormat");
                }
            }

            //重置数据流位置
            stream.Position = 0;

            return stream;
        }
闭包客 2017-09-14
  • 打赏
  • 举报
回复
四、
把函数内部调用的其他函数可能抛出的异常原封不动的注释抛出,会有两个问题。

一个是在函数的内部,调用的入参是在一个范围之内的,比如 image.Save(ms, format) 这个调用,我们可以知道 ms 和 format 的范围。ms 是在函数内部创建的,所以不可能是 null;format 我做了测试,image.RawFormat 不会是 null,所以按道理,是可以把注释的 System.ArgumentNullException 删除的。但是这个 Save 方法的作者,犯了一个错误,就是在 format 方法不为 null 的时候,他会抛出 System.ArgumentNullException 异常!!!这种情况发生在对原来的 Image做过缩放等处理的时候,image.RawFormat 的值会改变,变成一个 Guid 是 b96b3caa-0728-11d3-9d7b-0000f81ef32e 的实例,把这个实例作为参数调用 Save 方法,会抛出参数为 null 的异常。这就是典型的别的的程序员挖的坑:


另外一个是直接抛出别的函数可能抛出的异常,可能会造成异常难以理解,比如这个 ToStream 函数,调用者传入的 image 明明不是 null,却有可能抛出 System.ArgumentNullException 异常,这是很混乱的。所以要做一些处理,让调用者更好理解:

/// <exception cref="System.NullReferenceException">异常描述</exception>
/// <exception cref="System.ArgumentException">异常描述</exception>
/// <exception cref="System.Runtime.InteropServices.ExternalException">异常描述</exception>
public static Stream ToStream(Image image)
{
//System.NullReferenceException
ImageFormat format = image.RawFormat;

MemoryStream ms = new MemoryStream();

try
{
//System.ArgumentNullException
//System.Runtime.InteropServices.ExternalException
image.Save(ms, format);
}
catch (System.ArgumentNullException)
{
throw new System.ArgumentException("找不到图片的原格式");
}

return ms;
}

上面的代码把别的程序员的坑填上,抛出更好理解的错误。
zdg20042586 2017-08-24
  • 打赏
  • 举报
回复
学习了......
缪军 2017-08-23
  • 打赏
  • 举报
回复
1和2的性质是不一样的, 1.楼主说的是:是否考虑引发异常,这种情况大致就是那几个argument异常类的出处; 2.楼主说的是:是否捕捉异常,再抛出, 这个做法是不恰当的,捕获了某个(特定)异常,就不要再将其抛出,除非你要将其掩盖或者转义为其他类型的异常; 关于异常处理的策略,实际上还是要看设计需求, 比如说,有的函数会被设计成绝不会抛出异常, 具体的例子参见.net的源代码,比如,楼主可以比较一下这些方法的差别: Parse 和TryParse First 和 FirstOrDefault 仅仅就是这几个例子,已经涵盖了楼主说的情况
killxj2shit 2017-08-20
  • 打赏
  • 举报
回复
个人觉得是抛到最外面一级,在catch,除非有在finally里关闭流之类的东西
「已注销」 2017-08-19
  • 打赏
  • 举报
回复
抛不抛,我觉得看需求,一般对象是否为空是不抛异常,如果要抛,系统里面有N多个对象,抛个鬼啊,还是看需求,抛了异常,说明系统有错误,但是像image这个,如果只是用户没有选择一个图片给系统而已呢,肯定是提示“请选择一个图片”,而不是抛一个异常给用户。
小木当当 2017-08-18
  • 打赏
  • 举报
回复
zhujinqiang 2017-08-10
  • 打赏
  • 举报
回复
引用 18 楼 sp1234 的回复:
比如说,你检查 image 的大小,当它的颜色偏“黄颜色”的时候你跑出了一个自定义的 Exception,那么这是你的业务逻辑就是这样设计的。这个时候你可能会给别人一个文档说明这个抛出的自定义的异常的业务含义。 但是假设要任何人都罗列一些好像是“全面”的各种畅想,把任何可能的跟他的业务自定义设计无关的 Exception 都罗列出来,这就完全纠结概念而在实践中跑出了边际,跑到火星上去编程了。根本没有必要因为这种原因而忧心忡忡地去担心什么,根本不需要 try...catch。 要不要 try...catch,在于你开发中是不是主动测试。有的人只会盲目照抄例子,而不是以测试为驱动,那么他永远都是被动的思路,他永远不是在改进而是永远都在防御。
。。。小猫咪 2017-08-09
  • 打赏
  • 举报
回复
引用 16 楼 sp1234 的回复:
这个问题根本没有考虑到实际的原因,所以答案其实会偏离软件工程的目标。 你的 Release 的版本就是要容错所以当然需要 try...catch;而你的 Debug 版本就是要通过上万次测试回归让 debug 尽早跳处理来强迫系统进入调试环境,那么自然就应该尽可能去掉 try....catch。纠结它的名词儿概念,其实往往是根本没有直接进入其使用方法的,这就好像一个静止在树根底下不动的人永远追不上兔子一样,虽然好像知道“是什么”但是总也搞不明白“如何做”。 为什么要在 debug 的时候要让 bug 尽早调出来?因为只有 image 为 null 时造成的 bug 你才能追查一系列的软件设计 bug 嘛!开发时的目的就是求真,而不是自欺欺人。只有高强度的测试机制,你才知道该做什么事情,而不是“带着病”去写更多有毛病的代码。 但是 Release 版你自然就要容错。仅当你有几万、几十万次的测试,这时候在 Release 版本中再让“必要的” 几个 try...catch 起作用,这就好像是民航飞机都至少有两套飞行控制系统,它不是为了自欺欺人所以才冗余,而是在它每一套飞行控制系统都已经千锤百炼了之后仍然在 Release 版本中增加一个容错。这才是真正的容错思路。如果你认为 try...catch 就是为了隐瞒错误才这写代码,那么你从一开始就学了最令程序员不齿的开发观念了。
大佬厉害
Joyce_jk 2017-08-05
  • 打赏
  • 举报
回复
足球中国 2017-08-03
  • 打赏
  • 举报
回复
第一,第二都不需要。 你这个是返回的一个数据流还会有别的地方会用到这个函数。 如果你这里捕捉了错误,难道还要使用这个函数的程序再判断嘛?
zmidl 2017-08-03
  • 打赏
  • 举报
回复
个人感觉 try catch 用在不同环境下来保证程序安全的,不是用来检验逻辑错误的。
  • 打赏
  • 举报
回复
一个外围try catch搞定 。有问题会抛异常的
  • 打赏
  • 举报
回复
比如说,你检查 image 的大小 --> 比如说,你检查 image 的颜色
  • 打赏
  • 举报
回复
比如说,你检查 image 的大小,当它的颜色偏“黄颜色”的时候你跑出了一个自定义的 Exception,那么这是你的业务逻辑就是这样设计的。这个时候你可能会给别人一个文档说明这个抛出的自定义的异常的业务含义。 但是假设要任何人都罗列一些好像是“全面”的各种畅想,把任何可能的跟他的业务自定义设计无关的 Exception 都罗列出来,这就完全纠结概念而在实践中跑出了边际,跑到火星上去编程了。根本没有必要因为这种原因而忧心忡忡地去担心什么,根本不需要 try...catch。 要不要 try...catch,在于你开发中是不是主动测试。有的人只会盲目照抄例子,而不是以测试为驱动,那么他永远都是被动的思路,他永远不是在改进而是永远都在防御。
这不是鸭头 2017-08-03
  • 打赏
  • 举报
回复
引用 1 楼 closurer 的回复:
我先占个坑,再找时间来写写。
你占了坑,有时间再写也填不了你占的这个位置的坑。
  • 打赏
  • 举报
回复
这个问题根本没有考虑到实际的原因,所以答案其实会偏离软件工程的目标。 你的 Release 的版本就是要容错所以当然需要 try...catch;而你的 Debug 版本就是要通过上万次测试回归让 debug 尽早跳处理来强迫系统进入调试环境,那么自然就应该尽可能去掉 try....catch。纠结它的名词儿概念,其实往往是根本没有直接进入其使用方法的,这就好像一个静止在树根底下不动的人永远追不上兔子一样,虽然好像知道“是什么”但是总也搞不明白“如何做”。 为什么要在 debug 的时候要让 bug 尽早调出来?因为只有 image 为 null 时造成的 bug 你才能追查一系列的软件设计 bug 嘛!开发时的目的就是求真,而不是自欺欺人。只有高强度的测试机制,你才知道该做什么事情,而不是“带着病”去写更多有毛病的代码。 但是 Release 版你自然就要容错。仅当你有几万、几十万次的测试,这时候在 Release 版本中再让“必要的” 几个 try...catch 起作用,这就好像是民航飞机都至少有两套飞行控制系统,它不是为了自欺欺人所以才冗余,而是在它每一套飞行控制系统都已经千锤百炼了之后仍然在 Release 版本中增加一个容错。这才是真正的容错思路。如果你认为 try...catch 就是为了隐瞒错误才这写代码,那么你从一开始就学了最令程序员不齿的开发观念了。
加载更多回复(15)

110,499

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • Web++
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧