一,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 }
二,值类型的装箱和拆箱操做c#
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 }
三,泛型的出现(本节只简单介绍泛型对装箱和拆箱所起的做用,关于泛型的具体细节请参考下一篇文章)spa
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>;3d
List<T>;指针
Dictionary<Tkey,Tvalue>;
HashSet<T>;
在使用这些集合以前咱们必需要理解每一种集合的工做原理(没事本身能够实现一下),了解每一种集合的适合场合,这样才能写出高效的代码。
四,在设计时如何选择类和结构体
在面试的时候,咱们常常被问的一个问题(还有另一个问题,如何选择抽象类和接口,下次我会单独聊聊这个问题),下面咱们来聊聊在设计时应该如何选择结构体和类
都说程序是一门注重实践的学科,可是也只有熟悉理解了这些概论的东西,才能在实践时写出优秀的代码,有不对或者不合理的地方欢迎在下面讨论;