• linkedu视频
  • 平面设计
  • 电脑入门
  • 操作系统
  • 办公应用
  • 电脑硬件
  • 动画设计
  • 3D设计
  • 网页设计
  • CAD设计
  • 影音处理
  • 数据库
  • 程序设计
  • 认证考试
  • 信息管理
  • 信息安全
菜单
linkedu.com
  • 网页制作
  • 数据库
  • 程序设计
  • 操作系统
  • CMS教程
  • 游戏攻略
  • 脚本语言
  • 平面设计
  • 软件教程
  • 网络安全
  • 电脑知识
  • 服务器
  • 视频教程
  • JavaScript
  • ASP.NET
  • PHP
  • 正则表达式
  • AJAX
  • JSP
  • ASP
  • Flex
  • XML
  • 编程技巧
  • Android
  • swift
  • C#教程
  • vb
  • vb.net
  • C语言
  • Java
  • Delphi
  • 易语言
  • vc/mfc
  • 嵌入式开发
  • 游戏开发
  • ios
  • 编程问答
  • 汇编语言
  • 微信小程序
  • 数据结构
  • OpenGL
  • 架构设计
  • qt
  • 微信公众号
您的位置:首页 > 程序设计 >C#教程 > 解析C#中断言与异常的应用方式及异常处理的流程控制

解析C#中断言与异常的应用方式及异常处理的流程控制

作者:曹宗颖 字体:[增加 减小] 来源:互联网 时间:2017-05-28

曹宗颖 通过本文主要向大家介绍了c json解析,c语言试题及解析,c值解析,c语言考试题及解析,c语言实例解析精粹等相关知识,希望对您有所帮助,也希望大家支持linkedu.com www.linkedu.com

断言与异常(Assertion Vs Exception)
在日常编程实践中,断言与异常的界限不是很明显,这也使得它们常常没有被正确的使用。我也在不断的与这个模糊的怪兽搏斗,仅写此文和大家分享一下我的个人看法。我想我们还可以从很多角度来区别断言和异常的使用场景,欢迎大家的意见和建议。

异常的使用场景:用于捕获外部的可能错误

断言的使用场景:用于捕获内部的不可能错误

我们可以先仔细分析一下我们在.net中已经存在的异常。

  • System.IO.FileLoadException
  • SqlException
  • IOException
  • ServerException

首先,我们先不将它们看成异常,因为我们现在还没有在异常和断言之间划清界限,我们先将它们看成错误。

当我们在编码的第一现场考虑到可能会出现文件加载的错误或者服务器错误后,我们的第一直觉是这不是我们代码的问题,这是我们代码之外的问题。

例如下面这段代码

public void WriteSnapShot(string fileName, IEnumerable<DbItem> items)
    {
      string format = "{0}\t{1}\t{2}\t{3}\t{4}\t{5}";
      using (FileStream fs = new FileStream(fileName, FileMode.Create))
      {
        using (StreamWriter sw = new StreamWriter(fs, Encoding.Unicode))
        {
           ...
          foreach (var item in items)
          {
            sw.WriteLine(string.Format(format, new object[]{
              item.dealMan,
              item.version,
              item.priority,
              item.bugStatus,
              item.bugNum,
              item.description}));
          }
          sw.Flush();
        }
      }
    }
</div>

上面的代码在写入文件,很显然会导致IOException。稍微有经验的程序员都会考虑到IO上可能出问题,那我们应该如何处理这个问题呢?在这个上下文中,我们别无它法,只能让这个错误继续往上抛,通知上面一层的调用者,有一个错误发生了,至于上一层调用者会如何处理,不是这个函数要考虑的问题。但在这个函数中,要记得一点,将当前函数中所占用的资源释放了。因此,当我们不能控制的外部错误出现时,我们可以将其作为异常往上抛,这时,我们该使用异常。

现在再来看看断言,我们还是以下面的一段代码为例子。

public Entities.SimpleBugInfo GetSimpleBugInfo(string bugNum)
    {

      var selector = DependencyFactory.Resolve<ISelector>();

      var list = selector.Return<Entities.SimpleBugInfo>(
        reader => new Entities.SimpleBugInfo
        {
          bugNum = reader["bugNum"].ToString(),
          dealMan = reader["dealMan"].ToString(),
          description = reader["description"].ToString(),
          size = Convert.ToInt32(reader["size"]),
          fired = Convert.ToInt32(reader["fired"]),
        },
        "select * from bugInfo",
        new WhereClause(bugNum, "bugNum"));

      Trace.Assert(list != null);
      
      if (list.Count == 0)
        return null;
      else
        return list[0];

    }

</div>

当我贴出这段代码时,心情有些坎坷,因为我本人在这里也纠结了很久,这也是我一直没有将断言和异常划清界线的原因之一。

首先我们来回顾一下之前定义的断言使用场景:内部不可能发生的错误。

selector.Return这段代码是不是内部代码?如果我们能够修改Return中的代码,说明它是内部代码;反之,说明它是外部代码。对于内部代码,我们可以用断言来保护其逻辑的不变性,当断言被触发时,我们就可以确信是内部代码的错误,我们应该立即修复。

再纠结一下,假设Return是外部代码,我们没有办法去修改它。那么上面的代码可以有两种写法(如果你有更多的想法,请赐教)。

第一种,直接抛出异常。

If(list == null)
{
  throw new NullReferenceException();
}
</div>

第二种,调整代码。

if(list == null || list.Count == 0)
{
  return null;
}
else
{
  return list[0];
}

</div>

当然,还有一种就是什么也不做,让代码执行下去直至系统为你抛出空引用错误。但这种做法违背了防卸性编程的原则,我们总是应行尽早或离错误的发生地最近的地方处理错误,避免错误数据流向系统的其它地方,产生更加严重的错误。

总结

对异常或断言的使用取决于你要防卸的是一个内部错误还是外部错误以及你认为它是一个内部错误或外部错误。如果你决定防卸一个内部错误,那请果断使用断言,反之,请使用异常。

异常处理
异常处理对于流程的控制,就像抛出与捕获一样分为两个方面:

如果错误(或某种情况)发生,是否允许程序的控制流继续执行下去(异常的抛出)
如果当前有异常发生,当前的代码是否有机会让程序的控制流进入到一个合理的状态(异常的捕获)
我认为可以用以上两条,作为判断异常处理的准绳。其实大家现在应该可以发现,这个所谓的准绳的着重点在于异常对于流程的影响,而不再是在什么情况下才使用异常。

对于流程控制,最直接的莫过于下面这段代码

try
          {
            foreach (var lockGroup in lockGroups)
            {
 
              ...
 
              foreach (var newlock in lockGroup.ToArray())
              {
                ...
                if (diningBlocks.Exists(n => testLockRange.IsOverlapped(n.StartTime, n.EndTime)))
                {
                  status = LockStatus.InResourceBlock;
                  throw new LockException();
                }
 
                var diningAvail = availabilities.Find(n => n.Time == newlock.StartTime.TimeOfDay);
                if (diningAvail == null)
                {
                  status = LockStatus.Failed;
                  throw new LockException();
                }
 
                ...
                 
                if (newLockQuantity > diningAvail.MaxAvail && !canOverrideLock.AllowOverBook)
                {
                  status = LockStatus.Override;
                  throw new LockException();
                }
                else if (newLockQuantity + reservedQuantity + currentLockedAvail > diningAvail.MaxAvail && !canOverrideLock.AllowOverBook)
                {
                  status = LockStatus.Override;
                  throw new LockException();
                }
 
                ...
              }
            }
          }
          catch (LockException)
          {
            return new DiningLock[] { };
          }
</div>

在上面的代码中,有两层for循环,当最内层出现某种情况时,要求停止整个for循环的执行,显然用两个break是不行的,还得加入一个辅助变量。

但是,如果用异常,这个处理就简单多了。可以直接在最内层的抛出异常,在最外层(或是流程控制需要的地方)捕获异常。

在上面的代码中,异常处理起到了流程控制的作用,而不仅仅传递错误信息,对代码的简化做出了贡献。

</div>
分享到:QQ空间新浪微博腾讯微博微信百度贴吧QQ好友复制网址打印

您可能想查找下面的文章:

  • 解析C#的扩展方法
  • 解析C#多线程编程中异步多线程的实现及线程池的使用
  • 解析C#设计模式编程中备忘录模式的运用
  • 解析C#设计模式编程中外观模式Facade Pattern的应用
  • 解析C#设计模式编程中的装饰者模式
  • 解析C#设计模式编程中适配器模式的实现
  • 解析C#中的分部类和分部方法
  • 解析C#中的私有构造函数和静态构造函数
  • 解析C#面向对象编程中方法(method)的使用
  • 解析C#中的常量及如何在C#编程中定义常量

相关文章

  • 2017-05-28C#实现图片上传与浏览切换的方法
  • 2017-05-28C#基于SQLiteHelper类似SqlHelper类实现存取Sqlite数据库的方法
  • 2017-05-28C#清除字符串内空格的方法
  • 2017-05-28c# winform 关闭窗体时同时结束线程实现思路
  • 2017-05-28C#基于纯数学方法递归实现货币数字转换中文功能详解
  • 2017-05-28C# String Replace高效的实例方法
  • 2017-05-28C# 手动/自动保存图片的实例代码
  • 2017-05-28C#中多态、重载、重写区别分析
  • 2017-05-28C#实现最简单的文本加密方法
  • 2017-05-28C#实现去除Strings中空格的方法

文章分类

  • JavaScript
  • ASP.NET
  • PHP
  • 正则表达式
  • AJAX
  • JSP
  • ASP
  • Flex
  • XML
  • 编程技巧
  • Android
  • swift
  • C#教程
  • vb
  • vb.net
  • C语言
  • Java
  • Delphi
  • 易语言
  • vc/mfc
  • 嵌入式开发
  • 游戏开发
  • ios
  • 编程问答
  • 汇编语言
  • 微信小程序
  • 数据结构
  • OpenGL
  • 架构设计
  • qt
  • 微信公众号

最近更新的内容

    • C# 站点IP访问频率限制 针对单个站点的实现方法
    • C#中利用LINQ to XML与反射把任意类型的泛型集合转换成XML格式字符串的方法
    • C#中按引用传递与按值传递的区别,以及ref与out关键字的用法详解
    • 深入HTTP head的使用详解
    • 深入c# GDI+简单绘图的具体操作步骤(四)
    • C#中事件处理的个人体会
    • C#获取局域网MAC地址的简单实例
    • c#窗体传值用法实例详解
    • C#可空类型用法分析
    • linq语法基础使用示例

关于我们 - 联系我们 - 免责声明 - 网站地图

©2020-2025 All Rights Reserved. linkedu.com 版权所有