面试出现频率:基本上确定出现css
重要程度:10/10,身家性命般重要。一般这也是各类招聘工做的第一个要求,即“熟悉C#”的一部分。连这部分都不清楚的人,能够说根本不知道本身天天都在干什么。咱们每天使用C#写程序,但若是连C#基础的东西都不懂,怎么证实你“熟悉C#”呢?怎么让人觉的你对C#有兴趣呢?html
不少人去面试一发现面试官开始问基础题,就十分不爽,被淘汰了以后,还写博客说面试官垃圾,怎么不问问项目经历,哥但是作过很多项目的。却不知,面试官知道你作过那些项目,但一般来讲,若是那些项目不是牛逼透顶的级别(例如你参与了淘宝双11致使数据库并发问题的改进,或者AlphaGo的算法设计),或者正好是面试官所在公司须要的类型,则这并非什么很厉害的事情,是个程序员就有几个项目在身,“作过很多项目”的牛逼程度,差很少等于“活过20几年”(我都活了20几年了,我牛逼么?)。每一个人都有的东西,有什么好问的,问你了你能肯定你能答得比别人好么?可是若是你不能答出什么是装箱,你会引起面试官如下的猜测:前端
最重要的是,若是你装箱都不知道,面试官后面的N个连环问题立刻胎死腹中,他可能会一脸尴尬,由于“我只是用这个问题当破冰的啊,你怎么已经倒地了”,甚至不知道该问你啥,你才知道。C#话题就此终结,和蔼点的面试官,可能会问问你在简历上写的其余东西。但不管如何,你的价值已经狂跌了不止一个档次。jquery
在老外看来,这部份内容更为重要。不少老外,尤为是从优越国家来的那帮人,认为人找工做确定是为了兴趣,钱只不过是顺带得到的。他们根本不知道这世界上还有人会考虑一个自身毫无兴趣,仅仅是工资高的工做。若是他们发现,你连装箱都不知道是什么,他们会以为你不熟悉C#,对C#一点兴趣都没有,直接把你请出面试室,尽管你可能已经用C#写了几十个工程,手下可能已经有了几个小弟。也许你会央求面试官转换一个话题,例如问问设计模式,但我的认为,基础有问题的人,即便知道设计模式,作过不少项目,他写出来的asp.net代码多是一坨屎的概率要远远高于基础没问题,但彻底不懂asp.net的人。这也是为何不少老外的C#书籍前几章的内容好像都是些“毫无心义的”,“莫名其妙的”东西。CLR via C#更是其中的战斗机,你彻底不用看这本书,也能写出一个后台用asp.net MVC,前端html+css+jquery的ERP系统出来,先后端使用ajax通信,后端连数据库,用sql查数据,作CRUD。可是你不能凭借这个找到一个工资高的工做,由于会干这个的人实在是太多了,以致于不够值钱。若是你以为这已是了不得的成就,那么你这一辈子也就停留在这里了。若是你还想挣得更多,那么你就得会别人不会或者嗤之以鼻的东西。程序员
而工资高的工做,或对性能有很高的要求,或若是你写的代码太差,那真的会出大事,因此不能请基础差的人(固然好公司会有层层环境把关,但若是你的代码老出问题,你的水平弱于公司平均水平太多,他们也不会请你)。小公司尤为是外包,或者没什么名气的公司写的产品,自己也没有多少人用,崩溃了不会死人,因此代码垃圾一点无妨,只要能按时完成任务就得。面试
不少人反感基础题,一个很大的缘由在于,问问题的人不会问。若是问法是考定义,好比问“值类型与引用类型有何区别?” 这种问题的答案一查都找获得,也没有什么意义。较好的问法是,把概念问题融入到情景之中,或者构造一个连环问题。例如我遇到过的一个问题:你什么时候会考虑使用一个结构体?我以为一个不错的答案是”当这个对象全部的属性都是值类型时,例如刻画N维坐标系上的一个点”。若是面试者是如此做答,那么你能够继续问“能够用类型么?“这个时候,实际上仍是在问你值类型与引用类型有何区别,但相比直接问就天然不少。这个问题并非概念题,而是天天工做都会要遇到的。你总须要创建自定义的对象吧,那你就得从类型,结构,接口...中选择一个。ajax
须要理解的程度:熟悉值类型和引用类型的区别,以及它们之间是能够转换的(虽然这种转换基本上是必定要避免的)。对栈和堆上内存的活动有着清醒的认识。算法
参考资料:sql
公共类型系统(CTS)是用来描述IL的,它规定了IL能作什么,能定义什么样的变量,类中容许拥有什么成员等等。若是你写了一个不遵循CTS的语言(以及一个编译器),那么你的语言不能被当作是.NET平台的语言,编译出来的中间代码(若是有的话)不是IL。CTS和IL是全部.NET语言的爸爸。数据库
C#的数据类型能够分为值类型和引用类型。这是由于,CTS爸爸规定数据类型能够分为值类型和引用类型,并且C#实现了这部分功能。你能够开发一个遵循CTS的语言,但不实现任何值类型。
全部类型都从System.Object派生,接口是一个特例。下面是一些主要的System.Object提供的方法:
CLR要求全部对象都用new操做符来建立。对于值类型,你能够直接赋值,这至关于隐式的调用了new操做符。new操做符所作的事情有:
例以下面的代码中,C#首先将a初始化为5,而后再修改为10。
1 class SomeType 2 { 3 private static int a = 5; 4 5 static SomeType() 6 { 7 a = 10; 8 } 9 }
CLR via C#上的这个例子可让咱们透彻理解前一小节的内容以及内存中的各类活动。假设咱们有以下的定义。
若是代码以下图左下角所示,则开始执行的时刻,内存中的状况以下图:
当CLR扫描完M3方法以后,发现有两个引用类型Employee和Manager,故计算这两个类型及其全部基类型中定义的全部实例字段须要的字节数,在堆上创建两个类型对象,它们的构造相同:类型对象指针(TypeHandle),同步块索引,静态字段集合与方法表(储存了全部的方法)。
由于程序还没运行到第二行,因此栈上暂时尚未那个整型对象year。当运行完前2行时,栈中多了2个成员。一个Employee对象e被建立,但其没有指向任何东西。
但运行完第三行后,new关键字在堆上新建了一个实例,并返回这个引用,使得e指向一个Manager实例,这个实例的类型对象指针指向Manager类型对象。注意,一个类型不管有多少个实例,它们在堆中的对象都指向一个类型对象。另外须要关注的是,静态字段在类型对象中,而类型对象是惟一的,因此全部该类型的实例都指向一个类型对象,意味着一个实例更改了静态字段的值,全部其余实例都会受影响。
第四句调用了静态方法lookup。假设结果代表,Joe是公司的一名经理,则该方法将返回一个Manager对象。此时堆中将再次建立一个新的Manager对象,而e将会被指向这个新的对象。这个新的对象将会被初始化,Joe将做为其初始化的信息的一部分(再也不是默认的值,例如0或者Null)。
注意此时第一个Manager对象将会变成垃圾,等待垃圾回收器的回收。两个Manager对象指向一个Manager类型对象。
第五句代码将调用一个Employee类型的方法,假设返回5,那么year的值将变成5。
最后一句是一个虚方法,执行虚方法时,和实方法不一样。咱们要看虚方法有没有被人重写,还要根据调用虚方法的对象(e)肯定使用父类中的方法,仍是子类中重写的方法。根据上图发现,e实际上是一个指向Manager对象的东西,因而,咱们执行在Manager类中重写的那个方法。
注意若是在第四句中,Joe仅仅是一个Employee而不是Manager的话,那么堆中将不会有第二个Manager对象,而取而代之为一个新的Employee对象。最后一句也会执行在Employee中的方法,而不是Manager中的方法。
一个类型不管有多少个实例,它们在堆中的对象的类型对象指针都指向同一个类型对象。之因此只有一个类型对象,是由于不须要有多于一个(全部相同类型的定义都相同,都有相同的方法表)。因此,类型对象是储存类型静态成员最恰当的地方。类型对象由CLR在堆中的一个特殊地方(加载堆)建立(在第一次使用前),其中包括了类型的静态字段和方法表。建立完以后,就不会改变,经过这个事实,能够验证静态字段的全局(被全部同类型的实例共享)性。
类型对象是反射的重要操做对象。若是你要处理一个谜之对象,你不知道他有什么方法,那么你只能经过访问它的类型对象,你才知道这个谜通常的对象究竟包括什么方法。而后你就能够调用这些方法。GetType方法会返回对象指向的类型对象(包括静态成员和方法表)。
加载堆不受GC控制,因此静态字段和属性也不受GC控制。
1 int a = 123; // 建立int类型实例a 2 int b = 20; // 建立int类型实例b 3 var atype = a.GetType(); // 获取对象实例a的类型Type 4 var btype = b.GetType(); // 获取对象实例b的类型Type 5 Console.WriteLine(System.Object.Equals(atype,btype)); //输出:True 6 Console.WriteLine(System.Object.ReferenceEquals(atype, btype)); //输出:True
这意味着,内存中只有一个Int32类型对象,不然ReferenceEquals是不可能输出True的。
注意,类型对象也有类型对象指针,这是由于类型对象本质上也是对象。全部的类型对象的“类型对象指针”都指向System.Type类型对象。特别的,System.Type类型对象自己也是一个对象,内部的“类型对象指针”指向它本身。
属于BCL而非任何某个语言的类型叫作基元类型(Primitive Type)。你能够在mscorlib.dll中找到它们。例如:
IL 类型 C# 关键字 VB.NET关键字
System.Byte byte Byte
Sytem.Int16 short Short
System.Int64 int Integer
特别的,string映射到基元类型String。因此它们并无任何区别。
C#的数据类型能够分为值类型和引用类型,它们的区别主要有:
A a = new A();
A a2 = a;
此时在堆中只有一个A的实例,而a和a2都指向它。因此若是咱们更改了a中某个成员的值,a2中相应的成员也会更改。(这称为浅复制,与之对应的深复制则是要逐一复制对象全部成员的值,C#没有深复制的方法,要本身实现)值类型则彻底不一样,复制值类型将进行逐字段的复制,而没有指针参与。因此值类型是相互独立的。更改其中一个对另一个不会有影响。
类和结构是C#两个最主要的研究对象:
当试图表现例如点(X维坐标上的),形状(长,宽,面积等属性)等所有为值类型组成的对象时,考虑使用结构体。例如,若是声明一个 1000 个 Point 对象组成的数组,为了引用每一个对象,则需分配更多内存(堆上的1000个实例);这种状况下,使用结构能够节约资源。当数组不用时,若是是使用结构体,则1000个对象将立刻销毁,若是是使用类,则还要等GC,无形中提高了GC压力。
Console是一个类。
Int32是一个结构。其只含有两个常数的,Int32类型的字段(最小值和最大值),和若干方法。
这二者均位于基础类库mscorlib中。
类型的实例构造函数不能被继承。它负责将类型的实例字段初始化。对于静态字段,由静态构造函数负责。
若是类型没有定义任何构造函数,则编译器将定义一个没有参数的构造函数。其会简单地调用基类的无参构造函数。特别的,因为System.Object没有任何实例字段,因此它的构造函数什么也不作。
能够声明多个不一样的构造函数。能够利用this关键字来调用其它构造函数。
结构体的构造函数必须初始化它的全部成员。结构的构造函数不会被自动调用。
不能显式地为结构声明无参数的构造函数。
静态构造函数是一个特殊的构造函数,它会在这个类型第一次被实例化或引用任何静态成员以前,CLR在堆上建立类型对象时执行,它具备如下特色:
若是咱们不了解堆上的内存分配方式,对静态构造函数的理解会十分困难。为何是在建立第一个实例以前?为何不能直接调用?为何不能有参数?咱们彻底没法理解,只能经过死记硬背的方式记住这些性质。但若是你知道静态成员在类型对象中,并不存在于任何的实例中,可能你就会理解这些性质。
当咱们清楚的了解了类型对象以及CLR对类型对象的处理方式时,理解静态构造函数以及类型的静态成员就显得十分天然了。当建立第一个实例以前,堆上没有类型对象,因此要调用静态构造函数,当引用静态成员以前,堆上也没有类型对象,而静态成员属于类型对象,因此也要调用静态构造函数,这两种状况的最终结果,都是堆上最终出现了一个类型对象。由于类型对象只须要创建一次,因此这个静态构造函数也只能运行一次。
为何静态构造函数既没有访问修饰符,也没有参数?这是由于静态构造函数只负责初始化静态成员,只负责维护类型对象,它和类型的实例对象没有关系,因此你加入任何参数(你试图为非静态的字段或属性赋值?这是不可能的,由于根本就没有实例)都是没有意义的。
没法直接调用静态构造函数:如今显然十分容易理解了,由于类型对象只能有一个,若是能够随便被调用,则可能会创造出好几个类型对象,破坏静态字段的全局性。CLR也选择不把控制权交给用户。