雁过请留痕...
代码改变世界

随笔分类 -  C#

【进阶修炼】——改善C#程序质量(4)

2014-10-09 16:30 by xiashengwang, 524 阅读, 收藏, 编辑
摘要: 46, 显示释放资源,需要实现IDisposable接口。 最好按照微软建议的Dispose模式实现。实现了IDisposable接口后,在Using代码块中,垃圾会得到自动清理。 47, 即使提供了显示的释放方法,也应该在终结器中提供隐式实现。 因为我们不能保证用户会主动去调用这个释放方法,但我们要保证在垃圾回收时,这些资源能得到清理。 48, Dispose方法应该允许被多次调用。 我们可... 阅读全文

【进阶修炼】——改善C#程序质量(3)

2014-10-09 16:29 by xiashengwang, 271 阅读, 收藏, 编辑
摘要: 32, 总是优先考虑泛型。 泛型代码有很好的重复利用性,和类型安全性。 33, 应尽量避免在泛型类中声明静态成员。 静态成员达不到共享的目的。List和List是两个不同的类型,而静态成员是针对类型的。当然2个List之间是可以共享静态成员的,但为了不必要的混淆,应该避免使用静态成员。 34, 为泛型参数添加约束。 没有约束的参数,功能是有限的,添加了约束后,我们就可以使用约束类型的方法和属性... 阅读全文

【进阶修炼】——改善C#程序质量(2)

2014-10-09 16:28 by xiashengwang, 402 阅读, 收藏, 编辑
摘要: 16, 元素可变的情况下应避免用数组。 数组是定长的集合,可以考虑用ArrayList或List集合。ArrayList元素是object类型,有装箱的开销,性能较低。另外Array类提供了Array.CreateInstance来创建数组,Array.Copy来拷贝数组,但这牵涉到新数组的创建,会增加开销。 17, 多数情况下用foreach代替for循环。 18, Foreach不能代替f... 阅读全文

【进阶修炼】——改善C#程序质量(1)

2014-10-09 16:27 by xiashengwang, 598 阅读, 收藏, 编辑
摘要: 这是一个大纲形式的概要,以便自己可以花较少的时间反复阅读。在开发中,多加注意这些有用的建议,让自己成为一个更优秀的程序员。内容主要来自《编写高质量代码-改善C#程序的157个建议》(陆敏技),这本书写的真的很好,都是些实战经验的总结,建议大家购买,这其中的建议不仅仅适合于C#,只要你做.NET开发,阅读此书都会从中受益。同时,其他书籍和资料的一些好的编程建议,我也会不断更新到这里。 1,... 阅读全文

接口与virtual,override,new关键字

2014-07-14 17:56 by xiashengwang, 1799 阅读, 收藏, 编辑
摘要: 一,类继承接口1,首先我们定义一个简单的ITeacher接口,并定义一个Professor类继承它。 public interface ITeacher { void Print(); } public class Pro... 阅读全文

.Net程序帮助文档制作

2014-07-11 14:06 by xiashengwang, 3252 阅读, 收藏, 编辑
摘要: 一,准备工作1,首先介绍一款VS的代码注释插件GhostDoc你也许认为我们在代码中敲入///就能自动生成xml注释,但这种注释是没有说明文字的。而GhostDoc可以生成一些简单的说明文字,如果你的函数命名很规范的话,它生成的函数描述会很准确。并且它还能生成一些参数类型的附加说明。在你想生成代码注... 阅读全文

协变(covariant)和逆变(contravariant)

2014-01-21 16:15 by xiashengwang, 730 阅读, 收藏, 编辑
摘要: 我们知道子类转换到父类,在C#中是能够隐式转换的。这种子类到父类的转换就是协变。而另外一种类似于父类转向子类的变换,可以简单的理解为“逆变”。上面对逆变的简单理解有些牵强,因为协变和逆变只能针对接口和代理类型。而父类和子类之间不存在这种逆变的概念。协变和逆变的本质都是子类安全的转到父类的过程。下面就来加深下印象,先定义两个类Car和Baoma public class Car { } public class Baoma : Car { }明显Baoma(宝马)是Car的子类1,先来看看协变协变在C#中要用out关键字标明,用这个关键字就表示参数T只能用于函... 阅读全文

枚举Enum和常量0之间的恩怨

2013-11-29 15:13 by xiashengwang, 2683 阅读, 收藏, 编辑
摘要: 1,任何为0的常量表达式都能隐式的转换成枚举Enum。对于这一点,在程序中没少吃苦头。特别是对于函数重载的情况,往往让人一头雾水。看看下面的代码(摘自MSDN),你能猜到输出吗?public enum E{ Zero = 0, One = 1,} class A{ public A(string s, object o) { System.Console.WriteLine("{0} => A(object)", s); } public A(string s, E e) { System.Console.WriteLine("{0} => A(Enu 阅读全文

Lamda表达式的参数捕获,太酷了

2013-11-28 11:22 by xiashengwang, 6391 阅读, 收藏, 编辑
摘要: lamda表达式有了参数捕获这个功能,让Action这个委托变得无所不能。Action委托就是无参数,无返回值的一个代理类型。它只能对应于下面这种类型的函数声明。 public void Function() { //Do something } public void Function2() { //Do something } public void Function3() { //Do something }假设我们定义一个共通的执行... 阅读全文

.Net中的内存分配问题

2013-09-29 15:13 by xiashengwang, 584 阅读, 收藏, 编辑
摘要: 最近在测试的时候,要求测试内存不足的情况。我不想去开很多的程序来占用内存,那样太麻烦了,也不太精确。于是就写一个小程序来占用内存,想法很简单,就是声明一个Byte数组在占用内存,没想到这么简单的想法却没能正常工作,出乎我的所料,经过一番折腾,终于搞清楚了原因。using System;using System.Collections.Generic;using System.ComponentModel;using System.Data;using System.Drawing;using System.Linq;using System.Text;using System.Windows. 阅读全文

别误用IsDigit与IsNumber函数

2013-07-27 19:51 by xiashengwang, 21020 阅读, 收藏, 编辑
摘要: 1、起因最近发现程序中有一段控制TextBox数字输入的代码,相信大家都不会太陌生,如下: void int_KeyPress(object sender, KeyPressEventArgs e) { const char Delete = (char)8; if (!Char.IsDigit(e.KeyChar) && e.KeyChar != Delete) { e.Handled = true; } }乍一看,好像没有啥问题,但... 阅读全文

双行表头DatagridView的简单实现

2013-07-16 16:38 by xiashengwang, 6792 阅读, 收藏, 编辑
摘要: DatagridView默认不支持多行表头的实现,一些第三方的控件,比如Spread就可以,因此要实现这个功能,只能自己想办法了。介绍两种思路:1,用重写DataGridView的Paint等方法,可以重画表头,这个实现起来较为复杂,费时费力,此处略去。2,利用两个DataGridView,一个DataGridView用来显示第一行标题,另一个DatagridView用来显示第二行表头以及数据部分。实现中遇到一个问题,当列数很多的时候,第二个DatagridView会出现水平滚动条,拉动滚动条,第一个DatagridView并没有随着同步滚动,解决这个问题的方法是在第二个DatagridVie 阅读全文

不可小瞧的GetHashCode函数

2013-03-04 17:27 by xiashengwang, 10188 阅读, 收藏, 编辑
摘要: 要实现对象的相等比较,需要实现IEquatable,或单独写一个类实现IEqualityComparer接口。像List的Contains这样的函数,如果我们自己定义的对象不实现IEquatable接口,这个函数会默认调用object的Equels来比较对象,得出非预期的结果。先自定义一个类: ... 阅读全文

byte[]和int型的互转

2012-09-28 17:41 by xiashengwang, 3962 阅读, 收藏, 编辑
摘要: 这种转换有有意义的,比如可以将多个byte型的字段,转换后放到一个int字段中。例如color的a,r,g,b值,就可以放到一个int中,需要使用的时候,再从int转换成byte[]数组。它真正的意义还在于给我们提供了另一种存储数据的思想,它比较类似于位图存储法。下面记录下具体的实现方式。用位移运算(关键在于思想) //byte[] --> int byte a = 254, r = 240, g = 230, b = 220; int color = a << 24 | r << 16 | g << 8 | b; ... 阅读全文

c# 不安全代码之指针

2012-09-28 16:43 by xiashengwang, 473 阅读, 收藏, 编辑
摘要: 1,首先,编译器的选项里要打开“允许不安全代码”选项。2,代码块要放在unsafe关键字中,或对整个函数使用unsafe关键字。3,对于指向托管变量的指针分配必须放在fixed关键字中。例子: int i; unsafe { byte a = 254, r = 240, g = 230, b = 220; byte[] bytes = new byte[] { a, r, g, b }; //byte[] --> int ... 阅读全文

混合线程同步核心篇——自定义混合同步锁,Monitor,lock,ReaderWriterLockSlim・・・

2012-08-31 10:18 by xiashengwang, 2725 阅读, 收藏, 编辑
摘要: 前两篇博客,分别介绍了用户模式和内核模式的同步构造,由于它们各有优势和劣势。本文将介绍如何将这两者的优势结合在一起,构建一个性能良好的同步机制。一,实现一个简单的混合同步锁#region hybird lock/// /// 简单的混合同步锁/// private sealed class Hybi... 阅读全文

基元线程同步——内核模式构造(WaitHandle,EventWaitHandle,AutoResetEvent,ManualResetEvent,Semaphore,Mutex)

2012-08-29 17:46 by xiashengwang, 2809 阅读, 收藏, 编辑
摘要: 一、内核模式构造内核模式构造,采用的是windows操作系统来同步线程,比VolatileRead,VolatileWrite,Interlocked等用户模式的构造慢很多。相对于用户模式的构造,它也有自己的优点:1,不用像用户模式那样占着cpu“自旋”,浪费cpu资源。2,内核模式可同步在同一机器不同进程中运行的线程。3,可实现本地和托管线程相互之间的同步。4,一个线程可以一直阻塞,直到一个集合中的内核对象全部可用,或部分可用。(WaitAll,WaitAny)5,阻塞一个线程时,可以指定一个超时值,超过这个时间就解除阻塞。二、FCL提供的内核模式构造层次结构WaitHandle(抽象类) 阅读全文

基元线程同步——Interlocked Anything模式

2012-08-29 14:19 by xiashengwang, 964 阅读, 收藏, 编辑
摘要: 上一篇基元线程同步——基础,非阻塞同步(VolatileRead,VolatileWrite,volatile,Interlocked)已经对Interlocked类做了比较详细的分析,这一篇是对Interlocked类的一个模式进行补充说明。如果没用过Interlocked类,可以看看上面的这篇文章。这个模式的名字是Jeffrey给起的,它究竟要解决什么问题,我们为什么要用它?带着这些疑问,我们来看看它的应用场景。看看下面这个设定最大值的例子: private static Int32 Maximum(ref int target, int value) { ... 阅读全文

基元线程同步——基础,非阻塞同步(VolatileRead,VolatileWrite,volatile,Interlocked)

2012-08-25 11:22 by xiashengwang, 4021 阅读, 收藏, 编辑
摘要: 一、基元用户模式和内核模式。基元(Primitive):指代码中可以使用的最简单的构造。有两种基元构造:用户模式(user-mode)和内核模式(kernel-mode)。1,用户模式。它是用CPU指令来协调线程,这种协调是在硬件中发生的,所以速度会快于内核模式。但是也意味着,Windows操作系统永远也检测不到一个线程在一个基元用户模式构造上阻塞了。由于在一个基元用户模式构造上阻塞的线程永远不认为已经阻塞,所以线程池不会创建新的线程来替换这种阻塞的线程。另外,这些CPU指令只是阻塞线程极短的时间。缺点:只有Windows系统的内核才能停止一个线程的执行。用户模式中的线程可能会被系统抢占,但很 阅读全文

线程同步——优势、劣势

2012-08-25 10:16 by xiashengwang, 815 阅读, 收藏, 编辑
摘要: 一、线程同步好处:多个线程同时访问共享数据时,防止数据被损坏。二、线程同步带来的问题:1,实现比较繁琐,而且容易出错。必须对多个线程可能同时访问的所有数据,用额外的代码包围起来,以获得和释放一个同步锁。这需要由程序员来保证没有遗漏,对多线程共享的数据的加锁工作。并且,在程序完成时,需要进行压力测试以保证多个线程并发时,结果如预期。2,它会损害性能。获取和释放一个锁是需要时间的。因为需要额外的调用一些方法,并且需要协调调度下一个获得锁的线程。3,每次只能允许一个线程访问资源。这是锁的全部意义所在,但也是问题所在,因为阻塞一个线程可能会造成更多的线程被创建。三、线程同步建议:1,线程同步并不是一件 阅读全文