一,c#中的值类型和引用类型
众所周知在c#中有两种基本类型,它们分别是值类型和引用类型;而每种类型都可以细分为如下类型:
1 class SomRef 2 { 3 public int x; 4 } 5 struct SomeVal { 6 public int x; 7 } 8 class PRogram { 9 static void ValueTypeDemo() {10 SomRef r1 = new SomRef();//在堆上分配11 SomeVal v1 = new SomeVal();//在栈上分配12 r1.x = 5;//提领指针13 v1.x = 5;//在栈上修改14 SomRef r2 = r1;//只复制引用(指针)15 SomeVal v2 = v1;//在栈上分配并复制成员16 }17 }
二,值类型的装箱和拆箱操作
1 int i = 5;2 object o = i;3 int j = (int)o;
4 Int16 y=(Int16)o;
1 static void Main(string[] args)2 {3 int v = 5;4 object o = v;5 v = 123;6 Console.WriteLine(v+","+(int)o);7 }
通过上面的分析我们已经知道了,装箱和拆箱/复制操作会对应用程序的速度和内存消耗产生不利的影响(例如消耗内存,增加垃圾回收次数,复制操作),所以我们应该注意编译器在什么时候会生成代码来自动这些操作,并尝试手写这些代码,尽量避免自动生成代码的情况。
你能一眼从上面的代码中看出进行了几次装箱操作吗?正取答案是3次。分别进行了哪三次呢,我们来看一下:第一次object o=v;第二次在执行 Console.WriteLine(v+","+(int)o);时将v进行装箱,然后对o进行拆箱后又装箱。也就是说装箱过程总是在我们不经意的时候进行的,所以只有我们充分了解了装箱的内部机制,才能有效的避免装箱操作,从而提高应用程序的性能。所以对上面的代码进行如下修改可以减少装箱次数,从而提高性能:
1 static void Main(string[] args)2 {3 int v = 5;4 object o = v;5 v = 123;6 Console.WriteLine(v.ToString() + "," + ((int)o).ToString());//((int)o).ToString()代码本身没有任何意义,只为演示装箱和拆箱操作7 }
三,泛型的出现(本节只简单介绍泛型对装箱和拆箱所起的作用,关于泛型的具体细节请参考下一篇文章)
1 static void Main(string[] args) 2 { 3 ArrayList dateList = new ArrayList { 4 DateTime.Now 5 }; 6 7 IList<DateTime> dateT = new List<DateTime> { 8 DateTime.Now 9 };10 }
使用ArrayList时,每添加一个时间都会进行一次装箱操作,而使用List<DateTime>时就不会进行装箱操作,从而提高应用程序的性能。
Queue<T>;
Stack<T>;
List<T>;
Dictionary<Tkey,Tvalue>;
HashSet<T>;
在使用这些集合之前我们必须要理解每一种集合的工作原理(没事自己可以实现一下),了解每一种集合的适合场合,这样才能写出高效的代码。
四,在设计时如何选择类和结构体
在面试的时候,我们经常被问的一个问题(还有另外一个问题,如何选择抽象类和接口,下次我会单独聊聊这个问题),下面我们来聊聊在设计时应该如何选择结构体和类
都说程序是一门注重实践的学科,但是也只有熟悉理解了这些概论的东西,才能在实践时写出优秀的代码,有不对或者不合理的地方欢迎在下面讨论;
新闻热点
疑难解答