摘要:
建议90:不要为抽象类提供公开的构造方法 首先,抽象类可以有构造方法。即使没有为抽象类指定构造方法,编译器也会为我们生成一个默认的protected的构造方法。下面是一个标准的最简单的抽象类: 其次,抽象类的方法不应该是public或internal的。抽象类设计的本意是让子类继承,而不是用于生成实 阅读全文
posted @ 2017-12-06 17:57
指间的徘徊
阅读(215)
评论(0)
推荐(0)
摘要:
建议89:在并行方法体中谨慎使用锁除了建议88所提到的场合,要谨慎使用并行的情况还包括:某些本身就需要同步运行的场合,或者需要较长时间锁定共享资源的场合。在对整型数据进行同步操作时,可以使用静态类Interlocked的Add方法,这就极大地避免了由于进行原子操作长时间锁定某个共享资源所带来的同步性 阅读全文
posted @ 2017-12-06 17:55
指间的徘徊
阅读(218)
评论(0)
推荐(0)
摘要:
建议88:并行并不总是速度更快并行所带来的后台任务及任务的管理,都会带来一定的开销,如果一项工作本来就能很快完成,或者说循环体很小,那么并行的速度也许会比非并行要慢。看这样一个例子,我们比较在同步和并行状态下的时间消耗: 以上代码在笔者当前的双核PC机上的输出为:同步耗时:00:00:00.0005 阅读全文
posted @ 2017-12-06 17:39
指间的徘徊
阅读(224)
评论(0)
推荐(0)
摘要:
建议87:区分WPF和WinForm的线程模型WPF和WinForm窗体应用程序都有一个要求,那就是UI元素(如Button、TextBox等)必须由创建它的那个线程进行更新。WinForm在这方面的限制并不是很严格,所以像下面这样的代码,在WinForm中大部分情况下还能运行(本建议后面会详细解释 阅读全文
posted @ 2017-12-06 17:36
指间的徘徊
阅读(307)
评论(0)
推荐(0)
摘要:
建议86:Parallel中的异常处理建议85阐述了如何处理Task中的异常。由于Task的Start方法是异步启动的,所以我们需要额外的技术来完成异常处理。Parallel相对来说就要简单很多,因为Parallel的调用者线程会等到所有的任务全部完成后,再继续自己的工作。简单来说,它具有同步的特性 阅读全文
posted @ 2017-12-06 17:33
指间的徘徊
阅读(236)
评论(0)
推荐(0)
摘要:
建议85:Task中的异常处理在任何时候,异常处理都是非常重要的一个环节。多线程与并行编程中尤其是这样。如果不处理这些后台任务中的异常,应用程序将会莫名其妙的退出。处理那些不是主线程(如果是窗体程序,那就是UI主线程)产生的异常,最终的办法都是将其包装到主线程上。在任务并行库中,如果对任务运行Wai 阅读全文
posted @ 2017-12-06 17:30
指间的徘徊
阅读(629)
评论(0)
推荐(0)
摘要:
建议84:使用PLINQLINQ最基本的功能就是对集合进行遍历查询,并在此基础上对元素进行操作。仔细推敲会发现,并行编程简直就是专门为这一类应用准备的。因此,微软专门为LINQ拓展了一个类ParallelEnumerable(该类型也在命名空间System.Linq中),它所提供的扩展方法会让LIN 阅读全文
posted @ 2017-12-06 17:25
指间的徘徊
阅读(272)
评论(0)
推荐(0)
摘要:
建议83:小心Parallel中的陷阱Parallel的For和ForEach方法还支持一些相对复杂的应用。在这些应用中,它允许我们在每个任务启动时执行一些初始化操作,在每个任务结束后,又执行一些后续工作,同时,还允许我们监视任务的状态。但是,记住上面这句话“允许我们监视任务的状态”是错误的:应该把 阅读全文
posted @ 2017-12-06 17:20
指间的徘徊
阅读(250)
评论(0)
推荐(0)
摘要:
建议82:Parallel简化但不等同于Task默认行为建议81说到了Parallel的使用方法,不知道大家是否注意到文中使用的字眼:在同步状态下简化了Task的使用。也就是说,在运行Parallel中的For、ForEach方法时,调用者线程(在示例中就是主线程)是被阻滞的。Parallel虽然将 阅读全文
posted @ 2017-12-06 17:18
指间的徘徊
阅读(207)
评论(0)
推荐(0)
摘要:
建议81:使用Parallel简化同步状态下Task的使用在命名空间System.Threading.Tasks中,有一个静态类Parallel简化了在同步状态下的Task的操作。Parallel主要提供3个有用的方法:For、ForEach、Invoke。For方法主要用于处理针对数组元素的并行操 阅读全文
posted @ 2017-12-06 17:16
指间的徘徊
阅读(200)
评论(0)
推荐(0)
摘要:
建议80:用Task代替ThreadPool ThreadPool相对于Thread来说具有很多优势,但是ThreadPool在使用上却存在一定的不方便。比如:ThreadPool不支持线程的取消、完成、失败通知等交互性操作。ThreadPool不支持线程执行的先后次序。以往,如果开发者要实现上述功 阅读全文
posted @ 2017-12-06 16:57
指间的徘徊
阅读(415)
评论(0)
推荐(0)
摘要:
建议79:使用ThreadPool或BackgroundWorker代替Thread使用线程能极大地提升用户体验度,但是作为开发者应该注意到,线程的开销是很大的。线程的空间开销来自:1)线程内核对象(Thread Kernel Object)。每个线程都会创建一个这样的对象,它主要包含线程上下文信息 阅读全文
posted @ 2017-12-06 16:49
指间的徘徊
阅读(359)
评论(0)
推荐(1)
摘要:
建议78:应避免线程数量过多在多数情况下,创建过多的线程意味着应用程序的架构设计可能存在着缺陷。经常有人会问,一个应用程序中到底含有多少线程才是合理的。现在我们找一台PC机,打开Windows的任务管理器,看看操作系统中正在运行的程序有多少个线程。在笔者当前的PC机上,线程数最多的一个应用程序是某款 阅读全文
posted @ 2017-12-06 16:45
指间的徘徊
阅读(394)
评论(0)
推荐(0)
摘要:
建议77: 正确停止线程开发者总尝试对自己的代码有更多的控制。例如,“让那个还在工作的线程马上停止下来”。然而,并非我们想怎样就可以怎样的,这至少涉及两个问题。第一个问题 正如线程不能立即启动一样,线程也并不是说停就停的。无论采用何种方式通知工作线程需要停止,工作线程都会忙完手头最紧要的活,然后在它 阅读全文
posted @ 2017-12-06 16:43
指间的徘徊
阅读(266)
评论(0)
推荐(0)
摘要:
建议76: 警惕线程的优先级线程在C#中有5个优先级:Highest、AboveNormal、Normal、BelowNormal和Lowest。讲到线程的优先级,就会涉及线程的调度。Windows系统是一个基于优先级的抢占式调度系统。在系统中,如果有一个线程的优先级较高,并且它正好处在就绪状态,系 阅读全文
posted @ 2017-12-06 16:40
指间的徘徊
阅读(249)
评论(0)
推荐(0)
摘要:
建议75:警惕线程不会立即启动现代的大多数操作系统都不是一个实时的操作系统,Windows系统也是如此。所以,不能奢望我们的线程能够立即启动。Windows内部会实现特殊的算法以进行线程之间的调度,在某个具体的时刻,它会决定当前应该运行哪个线程。这反映到最底层就是某个线程分配到了一定的CPU时间,可 阅读全文
posted @ 2017-12-06 16:28
指间的徘徊
阅读(256)
评论(0)
推荐(0)
摘要:
建议74:警惕线程的IsBackground在CLR中,线程分为前台线程和后台线程,即每个线程都有一个IsBackground属性。两者在表现形式上的唯一区别是:如果前台线程不退出,应用程序的进程就会一直存在,必须所有的前台线程全部退出,应用程序才算退出。而后台进程则没有这方面的限制,如果应用程序退 阅读全文
posted @ 2017-12-06 16:26
指间的徘徊
阅读(290)
评论(0)
推荐(0)
摘要:
建议73:避免锁定不恰当的同步对象在C#中,让线程同步的另一种编码方式就是使用线程锁。线程锁的原理,就是锁住一个资源,使得应用程序在此刻只有一个线程访问该资源。通俗地讲,就是让多线程变成单线程。在C#中,可以将被锁定的资源理解成new出来的普通CLR对象。既然需要锁定的资源就是C#中的一个对象,我们 阅读全文
posted @ 2017-12-06 16:23
指间的徘徊
阅读(248)
评论(0)
推荐(0)
摘要:
建议72:在线程同步中使用信号量所谓线程同步,就是多个线程在某个对象上执行等待(也可理解为锁定该对象),直到该对象被解除锁定。C#中对象的类型分为引用类型和值类型。CLR在这两种类型上的等待是不一样的。我们可以简单地理解为在CLR中,值类型是不能被锁定的,即不能在一个值类型对象上执行等待。而在引用类 阅读全文
posted @ 2017-12-06 16:20
指间的徘徊
阅读(326)
评论(0)
推荐(0)
摘要:
建议71:区分异步和多线程应用场景初学者有时候会将异步和多线程混为一谈。如果对它们之间的区别不是很清楚,很容易写出下面这样的代码: 上面的代码模拟了在一个Winform窗体程序中,单击Button获取某个网页的内容并显示出来。可以预见,如果该网页的内容很多,或者当前的网络状况不太好,获取网页的过程会 阅读全文
posted @ 2017-12-06 15:43
指间的徘徊
阅读(350)
评论(0)
推荐(0)
摘要:
建议70:避免在调用栈较低的位置记录异常 并不是所有的异常都要被记录到日志,一类情况是异常发生的场景需要被记录,还有一类就是未被捕获的异常。未被捕获的异常通常被视为一个Bug,所以,对于它的记录,应该被视为系统的一个重要组成部分。 最适合记录异常和报告的是应用程序的最上层,这通常是UI层。假设存在这 阅读全文
posted @ 2017-12-06 15:40
指间的徘徊
阅读(257)
评论(0)
推荐(0)
摘要:
建议69:应使用finally避免资源泄漏 除非发生让应用程序中断的异常,否则finally总是会先于return执行。finally的这个语言特性决定了资源释放的最佳位置就是在finally块中;另外,资源释放会随着调用堆栈由下往上执行。下面的代码验证了这一点,先定义一个需要释放的类: 再来模拟一 阅读全文
posted @ 2017-12-06 15:34
指间的徘徊
阅读(262)
评论(0)
推荐(0)
摘要:
建议68:从System.Exception或其他常见的基本异常中派生异常 微软建议:从System.Exception或其他常见基本异常之一派生异常。在Visual Studio中输入Exception,然后按快捷键Tab,VS会自动创建一个自定义异常类: 这是一个标准的自定义异常,它同时告诉你, 阅读全文
posted @ 2017-12-06 15:25
指间的徘徊
阅读(312)
评论(0)
推荐(0)
摘要:
建议67:慎用自定义异常 除非有充分的理由,否则不要创建自定义异常。如果要对某类程序出错做特殊处理,那就自定义异常。需要自定义异常的理由如下: 1)方便测试。通过抛出一个自定义的异常类型实例,我们可以使捕获的代码精确的知道所发生的事情,并以符合的方式进行恢复。 2)逻辑包装。自定义异常可以包装多个其 阅读全文
posted @ 2017-12-06 15:23
指间的徘徊
阅读(265)
评论(0)
推荐(0)
摘要:
建议66:正确捕获多线程中的异常 多线程的异常处理需要采用特殊的方式。一下这种方式会存在问题: 应用程序并不会在这里捕获线程的异常,而是会直接退出。从.NET2.0开始,任何线程上未处理的异常都会导致应用程序的退出(先会触发APPDomain的UnhandledException)。上面的代码中的t 阅读全文
posted @ 2017-12-06 15:22
指间的徘徊
阅读(363)
评论(0)
推荐(0)
摘要:
建议65:总是处理未捕获的异常 处理为捕获的异常是每个应用程序具备的基本功能,C#在APPDomain提供了UnhandledException事件来接收未捕获到的异常的通知。常见的应用如下: 未捕获异常通常就是运行时期的Bug,我们可以在AppDomain.CurrentDomain.Unhand 阅读全文
posted @ 2017-12-06 15:13
指间的徘徊
阅读(282)
评论(0)
推荐(0)
摘要:
建议64:为循环增加Tester-Doer模式而不是将try-catch置于循环内 如果需要在循环中引发异常,你需要特别注意,应为抛出异常是一个相当影响性能的过程。应该尽量在循环当中对异常发生的一些条件进行判断,然后根据条件进行处理。 做个测试: 输出为: 796 0 以上代码中,我们预见了代码肯能 阅读全文
posted @ 2017-12-06 15:12
指间的徘徊
阅读(245)
评论(0)
推荐(0)
摘要:
建议63:避免“吃掉”异常 嵌套异常是很危险的行为,一不小心就就会将异常堆栈信息,也就是真正的Bug出处隐藏起来。这还不是最严重的,最严重的就是“吃掉”异常,即捕获,然后不向上层throw。 避免“吃掉”异常,并不是说不应该“吃掉”异常,而是这里有个重要原则:该异常可被预见,并且通常情况它不能算是一 阅读全文
posted @ 2017-12-06 15:01
指间的徘徊
阅读(288)
评论(0)
推荐(0)
摘要:
建议62:避免嵌套异常 应该允许异常在调用堆栈上往上传,不要过多的使用catch,然后再throw。过多的使用catch会带来两个问题: 1)代码更多了。这看上去好像你根本不知道怎么处理异常,所以你总是不停地catch。 2)隐藏了堆栈信息,使你不知道真正发生异常的地方。 无故地嵌套是我们应该极力避 阅读全文
posted @ 2017-12-06 15:00
指间的徘徊
阅读(264)
评论(0)
推荐(0)
摘要:
建议61:避免在finally内撰写无效代码 在阐述建议之前,需要先提出一个问题:是否存在一种打破try-finally执行顺序的情况,答案是:不存在(除非应用程序本身因为某些很少出现的特殊情况在try块中退出)。应该始终认为finally内的代码会在方法return之前执行,哪怕return在tr 阅读全文
posted @ 2017-12-06 14:53
指间的徘徊
阅读(383)
评论(1)
推荐(0)
摘要:
建议60:重新引发异常时使用Inner Exception 当捕获了某个异常,将其包装或重新引发异常的时候,如果其中包含了Inner Exception,则有助于程序员分析内部信息,方便代码调试。 以一个分布式系统为例,在进行远程通信的时候,可能会发生的情况肯能会有: 1)网卡被禁用或者网线断开,此 阅读全文
posted @ 2017-12-06 14:51
指间的徘徊
阅读(438)
评论(0)
推荐(0)
摘要:
建议59:不要在不恰当的场合下引发异常 常见的不易于引发异常的情况是对在可控范围内的输入和输出引发异常。 此方法起码有两个地方欠妥: 1)判读Age不能为负数。这是一个正常的业务逻辑,它不应该被处理为一个异常。 2)应采用Tester-Doer来验证输入。 应该添加一个Tester方法: 调用代码: 阅读全文
posted @ 2017-12-06 14:49
指间的徘徊
阅读(297)
评论(0)
推荐(0)
摘要:
建议58:用抛出异常代替返回错误代码 CLR异常机制的优点: 正常控制流会被立即中止,无效值或状态不会在系统中继续传播。 提供了统一的处理错误的方法。 提供了在构造函数、操作符重载及属性中报告异常的遍历机制。 提供了异常堆栈,便于开发者定位异常发生的位置。 不应该将异常机制用于正常控制流中,异常的发 阅读全文
posted @ 2017-12-06 14:34
指间的徘徊
阅读(378)
评论(0)
推荐(0)
摘要:
建议57:实现ISerializable的子类型应负责父类的序列化 我们将要实现的继承自ISerializable的类型Employee有一个父类Person,假设Person没有实现序列化,而现在子类Employee却需要满足序列化的场景。不过序列化器并没有默认处理Person类型对象,这些事情只 阅读全文
posted @ 2017-12-06 11:51
指间的徘徊
阅读(269)
评论(0)
推荐(0)
摘要:
建议56:使用继承ISerializable接口更灵活地控制序列化过程 接口ISerializable的意义在于,如果特性Serializable,以及与其像配套的OnDeserializedAttribute、OnDeserializingAttribute、OnSerializedAttribu 阅读全文
posted @ 2017-12-06 11:50
指间的徘徊
阅读(1265)
评论(0)
推荐(1)
摘要:
建议55:利用定制特性减少可序列化的字段 特性(attribute)可以声明式地为代码中的目标元素添加注释。运行时可以通过查询这些托管块中的元数据信息,达到改变目标元素运行时行为的目的。System.Runtime.Serialization命名空间下,有4个这样的特性: OnDeserialize 阅读全文
posted @ 2017-12-06 11:47
指间的徘徊
阅读(380)
评论(0)
推荐(0)
摘要:
建议54:为无用字段标注不可序列化 序列化是指这样一种技术:把对象转变成流。相反过程,我们称为反序列化。在很多场合都需要用到这项技术。 把对象保存到本地,在下次运行程序的时候,恢复这个对象。 把对象传到网络中的另外一台终端上,然后在此终端还原这个对象。 其他场合,如:把对象赋值到系统的粘贴板中,然后 阅读全文
posted @ 2017-12-06 11:45
指间的徘徊
阅读(504)
评论(0)
推荐(0)
摘要:
建议53:必要时应将不再使用的对象引用赋值为null 在CLR托管的应用程序中,存在一个“根”的概念,类型的静态字段、方法参数、以及局部变量都可以作为“根”的存在(值类型不能作为“根”,只有引用类型的指针才能作为“根”)。 局部变量在代码运行过程中会在内存中创建一个“根”。在一次垃圾回收中,垃圾回收 阅读全文
posted @ 2017-12-06 11:41
指间的徘徊
阅读(409)
评论(0)
推荐(0)
摘要:
建议52:及时释放资源 垃圾回收机制自动为我们隐式地回收了资源(垃圾回收器会自动调用终结器),那我们为什么要主动释放资源呢? 这是一个WinForm窗体程序的例子,在这个示例中,单击一个按钮负责打开一个文件,单击另一个按钮负责回收说有“代”(代的概念会在下文详细指出)的垃圾。如果连续两次单击打开文件 阅读全文
posted @ 2017-12-06 11:39
指间的徘徊
阅读(352)
评论(0)
推荐(0)
摘要:
建议51:具有可释放字段的类型或拥有本机资源的类型应该是可释放的 在建议50中,我们将C#中的类型分为:普通类型和继承了IDisposable接口的非普通类型。非普通类型除了包含那些托管资源的类型外,本身还包含一个非普通类型的字段。 在标准的Dispose模式中,我们对非普通类型举了一个例子:一个非 阅读全文
posted @ 2017-12-06 11:13
指间的徘徊
阅读(454)
评论(0)
推荐(0)
摘要:
建议50:在Dispose模式中应区别对待托管资源和非托管资源 真正资源释放代码的那个虚方法是带一个bool参数的,带这个参数,是因为我们在资源释放时要区别对待托管资源和非托管资源。 提供给调用者调用的显式释放资源的无参Dispose方法中,调用参数是true: 这表明,这时候代码要同时处理托管资源 阅读全文
posted @ 2017-12-06 11:09
指间的徘徊
阅读(343)
评论(0)
推荐(0)
摘要:
建议49:在Dispose模式中应提取一个受保护的虚方法 在标准的Dispose模式中,真正的IDisposable接口的Dispose方法并没有做实际的清理工作,它其实是调用了下面的这个带bool参数且受保护的的虚方法: 之所以提供这样一个受保护的虚方法,是因为考虑了这个类型会被其他类型继承的情况 阅读全文
posted @ 2017-12-06 11:07
指间的徘徊
阅读(280)
评论(0)
推荐(0)
摘要:
建议48:Dispose方法应允许被多次调用 一个类型的Dispose方法应该允许被多次调用而不抛出异常。鉴于此,类型内部维护了一个私有的bool变量disposed,如下: 在实际清理代码的方法中,加入一下判断: 这意味着,如果类型已经被清理过,那么清理工作将不再进行。 对象被调用过Dispose 阅读全文
posted @ 2017-12-06 10:41
指间的徘徊
阅读(258)
评论(0)
推荐(0)
摘要:
建议47:即使提供了显式释放方法,也应该在终结器中提供隐式清理 在标准的Dispose模式中,我们注意到一个以~开头的方法,如下: 这个方法叫做类型的终结器。提供类型终结器的意义在于,我们不能奢望类型的调用者肯定会主动调用Dispose方法,基于终结器会被垃圾回收这个特点,它被用作资源释放的补救措施 阅读全文
posted @ 2017-12-06 09:52
指间的徘徊
阅读(275)
评论(0)
推荐(0)

浙公网安备 33010602011771号