C#语言是与微软的.NET框架紧密地联系在一起的,而.NET框架是微软.NET战略的核心,为了更好的理解C#语言,我们必须了解一些.NET框架的基本知识。.NET框架是为开发应用程序推出的一个编程平台,它主要为编写应用程序提供两方面的支持,一是它管理代码的执行过程,二是它为代码提供类库支持。

(1)公共语言运行时CLR

.NET平台下编写的程序一般都在公共语言运行时(Common Language Runtime,CLR)的管理下运行,它负责运行代码,确保代码的安全性和准确性,又负责内存管理、线程调度等核心服务,通常把在CLR控制下运行的代码称为托管代码(Managed Code)。

(2)FCL类库

.NET为我们提供了一个内容丰富的.NET框架基础类库(Framework Class Library,FCL),如果将C#程序比喻为一座大厦,那么大厦的设计思想就是面向对象编程,而建筑大厦的材料则来自于.NET框架基础类库,我们可以像使用钢筋、水泥、砖块一样使用FCL中的类构建应用程序大厦。因此学习C#的一个重点就是学习FCL类库中的常用类。

1. C#为何采用两次编译

1)为了提高性能

因为JIT编译中程序运行时发生,这时编译器已经知道系统使用何种类型的CPU,可以针对该CPU特性在JIT编译过程中进行代码优化(比如可以更高效地利用CPU 的寄存器,在适当的情况下实施低级代码优化(常量重叠、拷贝复制、取消范围检查、取消常规副表达式以及方法内联等),可以在代码执行期间监控当前的物理和虚拟内存需求从而更高效地利用内存等),另外,虽然程序运行代码首次由中间语言编成为机器语言时,性能会稍有损失,但由于中间语言可以非常快速地转换为机器语言,并且被优化的程序代码往往被成百上千次使用,第一次编译造成的这点性能损失显得微不足道,C#两次编译的优势就显现出来了。

2)语言互操作性

MSIL 为不同编程语言的互操作性提供了可能,不同语言编写的组件最终都编译为中间语言,然后组成一个完整的程序。这样就能让使用C#、Visual Basic、Visual C++的开发人员一起完成同一项目。

3)平台无关性

Mono项目,以及现在正式推出的.NET Core,使基于.NET程序能够运行在各种操作系统平台上。

2.强数据类型

中间语言是基于强数据类型的,即每一个变量都有明确的数据类型。虽然有时强数据类型会降低性能,但会在语言的互操作性、垃圾回收、安全性、应用程序域等方面获得更多的好处。

1)通用类型系统

由于不同编程语言的数据类型和语法都有所不同,由此.NET为中间语言制定了一个通用类型系统(Common Type System,CTS),它定义了一系列标准的基本数据类型,不管你用什么语言编写程序,程序中的变量最终都被转换为这些基本数据类型。

通用类型系统不仅指定了基本数据类型,还定义了一个内容丰富的类型层次结构,允许用户通过这些基本类型构造自己需要的类型,比如数组、结构、类等。如图所示。

(2)公共语言规范

除了通用类型系统外,.NET 框架还制定了一套公共语言规范(Common Language Specification,CLS)。每种语言都有一套自己的语法规则集,而恰恰CLS 就是这些集合的交集,所以它能被.NET 上的所有语言支持。通俗地说就是公共语言规范中的语法规则在所有.NET 语言中都成立。如此一来,符合CLS 规范的代码转换为中间语言后就可以被.NET 上任何语言访问,从而确保不同语言的互操作性。编写不符合CLS 规范的代码是完全可以的,但这时就不能保证不同语言间的互操作性。所以在编写用于共享的类时,一般只用完全兼容CLS 的代码,以增强类的交互性;在私有类中,可以编写非CLS 代码,因为私有类不用来交互。C#中不兼容CLS 的特性非常少。

3. 类型的判定、命名空间和装箱拆箱

(1)类型的判定

通过下面几种方法,可以轻易获取变量的类型信息:

Sizeof()运算符,通过它可获知数据类型在内存中占用几个字节。如sizeof(int)。

typeof(),通过它可以获取数据类型的通用数据类型名,此运算符的参数只能是类型。如typeof(int)得到System.Int32。

GetType(),如果想要获取某个变量的类型,需要使用该变量的GetType()方法,此方法继承自Object类,例如对于int t;string str=t.GetType();。

结合 GetType()方法和typeof 运算符,我们就可以检验变量是否为某种类型。kitty.GetType() == typeof(Cat))。is 运算符,is 运算符检验某个对象是否为某种类型,而且用法更为简洁,例如if(kitty is Cat){}。这两种判断变量类型的方式有一点区别,即当对象和类型之间是继承关系时,is运算符仍然返回true。

(2)命名空间

命名空间是用来组织类的,它避免了重名的问题。System是.Net预定义的一个命名空间,它包含了大量常用类。如果在文件开头使用了using 语句,在使用相应命名空间中的类时,就不必添加命名空间前缀了。.NET 建议在大多数情况下,都至少要提供两个嵌套的命名空间,第一个是公司名,第二个是技术名或软件名。这么做可以尽量保证不与其它组织编写的命名空间冲突。例如Microsoft.Win32. Registry类。

(3)装箱拆箱

在C#中,一切变量都可以看作对象,所有值类型数据都可以通过隐式的装箱操作转换为引用型对象,装箱操作的优点在于可以像操作对象那样操作值类型变量。操作方法例如:int n=3;Object obj=n;。对于装入箱中的值类型数据,可以通过拆箱(Unboxing)操作释放出来,拆箱操作要用显式转换,例如int i=(int)obj;。当一个方法的参数类型不能确定时,装箱操作就非常有用,例如一个用来存储各种物品的仓库类:

class Storehouse

{ public Object [] items;

private int count;

public Storehouse(int size)

{ items=new Object[size];count=0;}

public void Add(Object obj)

{

if(count<items.Length)

{  items[count]=obj;

count++;}

else

{Console.WriteLine(“仓库已满”);}

}

}

3.异常

异常(Exception)就是程序执行期间发生的问题,原因并不总在程序员,比如用户输入了非法数据,要读取的文件不存在等等。如果不处理这些异常,程序可能会崩溃,但如果在程序中过多的处理这些异常,会使程序结构不清晰。为此,C#为我们提供了一套完美的方案,在程序主线之外处理异常,不但使程序更加健壮、更加容错,而且保持了程序结构的清晰。

(1)捕获异常——try-catch结构

一般情况下我们需要对可能的异常情况进行处理,这时就需要捕获并处理异常。在C#中用try-catch 结构捕获并处理异常。把可能出现异常的语句放在 try 块中,把异常发生后的处理代码放在catch 块中。产生异常后CLR会在try 块后面寻找匹配的catch 块,并执行该块中的语句。

(2)收尾工作——try-catch-finally结构

在某些问题中,不论是否出现异常,都要进行一些收尾工作,这些收尾工作常放在finally 块中。可能发生异常的代码放在try 块中,异常处理代码放在catch 块中,不管是否发生异常,

程序都要执行finally 块中的代码。

例如,程序经常动态申请资源,比如打开某个文件,并从中读写数据。操作系统通常不允许多个程序同时读写同一个文件,所以读写完文件后,应及时关闭文件(即释放资源),以便其它程序使用。如果不关闭文件,就会发生资源泄露。这些释放资源的代码通常放在finally 块,不管是否发生异常,资源均被释放。

注意:try 块和catch 块、finally 块一起构成try 语句,try 块是关键字try 后用大括号括起来的语句块。如果 try 块后面有catch 块,则finally 块是可选的;如果try 块后面没有catch 块,则必须跟一个finally 块;如果既有catch 块又有finally 块,finally 块必须放在最后。

(3)抛出异常——throw语句

.NET 可以自动检测并抛出常见异常,但有时我们需要人工抛出异常。

try

{

Console.Write("请输入一个0 到10 之间的整数:");

int number = Convert.ToInt32(Console.ReadLine());

if (number < 0 || number > 10)

{

throw new ArgumentOutOfRangeException();

}

else

{

Console.WriteLine("你输入的整数是:{0}", number);

}

}

catch (ArgumentOutOfRangeException)

{

Console.WriteLine("你输入的整数超出范围!");

}

finally

{ Console.WriteLine("谢谢!"); } }

在C#中使用thow 语句抛出异常,其一般格式如下图所示,该语句先通过new 运算符创建异常类ArgumentOutOf RangeException 的一个对象,然后通过throw 语句抛出。当程序遇到throw 语句时,会立即停止执行try 块中的语句,转而执行匹配的catch 块中的语句。

4.NET中的异常类

(1)常见异常类

.NET 提供了丰富的异常类型,所有的异常类型都派生于Exception 类。下图列举出了一些常见的异常。

类大多在System 命名空间中,而IOException 类及其派生类在System.IO命名空间中(这个命名空间用于处理数据的读写)。一般情况下,异常没有特定的命名空间,哪个类生成异常,异常就放在哪个类所在的命名空间。Exception 类有两个非常重要的派生类——SystemException 和ApplicationException。.NET 中预定义的异常类都派生于SystemException 类,而用户自定义的异常类都应派生于ApplicationException 类。由于派生类对象属于基类,所以当有多个 catch 块时,要按从具体到一般的顺序由上往下排列,基类必须放在最后,否则捕捉派生类异常的catch 块永远没机会被执行。

(2)获取方法的异常帮助信息

还可以不给catch 块指定异常类型,这时它可以捕获任何异常。如想查找方法Convert.ToInt32(String)的异常,可以直接在vs ide中按F1,即可在帮助中找到Convert.ToInt32 (String)方法的文档,其中会有一节用来描述和该方法相关的异常。

(3)异常类的属性

Exception类和其他一般类一样,有几个公有属性,通过这些属性可以非常方便的了解异常信息。其中比较重要的两个属性是Message和StackTrace。属性Message用于描述异常的原因,属性StackTrace用于描述异常的堆栈信息,即发生异常位置。例如

catch (DivideByZeroException e)

{ Console.WriteLine("Message:" + e.Message);

Console.WriteLine("StackTrace:" + e.StackTrace); }

(4)自定义异常

大多数情况下,我们使用.Net 预定义的异常类,必要时我们也可以针对程序中的问题创建新的异常类。用户定义的异常类都直接或间接继承于ApplicationException 类。例如:

Class NegativeNumberException:ApplicatioinException

{

//属性Message 被直接初始化为字符串"对负数进行非法操作"

public NegativeNumberException():base(“对负数进行非法操作”){}

public NegativeNumberException(string message):base(message){}

}

异常类的名称最好和故障相关联,并以“Exception”结尾。

C# 篇基础知识4——.NET的基础概念的更多相关文章

  1. Redis 02: redis基础知识 + 5种数据结构 + 基础操作命令

    Redis基础知识 1).测试redis服务的性能: redis-benchmark 2).查看redis服务是否正常运行: ping 如果正常---pong 3).查看redis服务器的统计信息: ...

  2. C++ 基础知识回顾(string基础、智能指针、迭代器、容器类)

    [1] string基础 [1.1] string 的构造 #include <iostream> #include <string> int main() { using n ...

  3. 【基础知识】Asp.Net基础三

    服务器端控件一般用于访问量不高的网站,要做到物尽其用. 服务器端控件: FIleUpload控件:向服务器上传文件 if (this.FileUpload1.HasFile) { // Path.Ge ...

  4. 《Java基础知识》Java继承的概念和实现

    继承时类和类之间的关系,是一个很简单很直观的概念,与显示生活中的继承(例如儿子继承了父亲财产)类似. 继承可以理解为一个类从另一个类中获取方法和属性的过程.如果类B继承于类A,那么类B就拥有类A的属性 ...

  5. 《Java基础知识》Java线程的概念

    按照规划,从本篇开始我们开启『并发』系列内容的总结,从本篇的线程开始,到线程池,到几种并发集合源码的分析,我们一点点来,希望你也有耐心,因为并发这块知识是你职业生涯始终绕不过的坎,任何一个项目都或多或 ...

  6. java基础知识-序列化/反序列化-gson基础知识

    以下内容来之官网翻译,地址 1.Gson依赖 1.1.Gradle/Android dependencies { implementation 'com.google.code.gson:gson:2 ...

  7. java基础知识——程序员面试基础

    一.面向对象的特征有哪些? 答:①.抽象:抽象是忽略一个主题中与当前目标无关的那些方面,一边更充分的注意与当前目标有关的方面.抽象并不打算了解全面问题,而是选择其中的一部分,暂时不用部分细节.抽象包括 ...

  8. Spring 基础知识(一)基本概念 DI、IOC、AOP

    DI(依赖注入) 和IOC(控制反转)都是一种设计思想,要理解他们,让我们从coding中的一些痛点入手. 依赖注入 Dependency Injection : 如果A类要使用B类的一个方法,首先必 ...

  9. 【基础知识】ASP.NET[基础一(ashx)]

    一.ASP.NET介绍 1.ASP.NET包括: 一般处理程序(ashx):WebForm ( aspx ):MVC(Model view con~~): 2.ASP.NET的常用文件(重点): 1& ...

随机推荐

  1. 有个网站秒破mdb访问密码

    http://tools.bugscaner.com/crackmdb/网站

  2. 3_08_MSSQL课程_Ado.Net_子查询

    子查询 1.把一个查询结果作为一个表来使用,就是子查询. 2.把一个查询结果作为一个 表达式进行使用就是子查询. (分页Sql)

  3. 几个原生js知识

    1.document.documentElement 返回根节点 html. 2.原生方法获取一个对象的某个样式的值. function getStyle(obj, attr) { if(obj.cu ...

  4. 3.ORM框架一对多的关系及使用

    一对多就是主键与外键的关系,通过一个用户表,角色表进行举例子 角色表role:有外键,对应的是user表的主键 用户表users: from flask import Flask, render_te ...

  5. PTA的Python练习题(十一)

    从 第4章-3 猴子吃桃问题 继续 1. a=eval(input()) def count(n): b=1 for i in range(n-1): b=(b+1)*2 return b print ...

  6. [转]使用Struts 2防止表单重复提交

    转自 用户重复提交表单在某些场合将会造成非常严重的后果.例如,在使用信用卡进行在线支付的时候,如果服务器的响应速度太慢,用户有可能会多次点击提交按钮,而这可能导致那张信用卡上的金额被消费了多次.因此, ...

  7. IDEA下的SVN设置以及TortoiseSVN安装后bin目录下没有svn.exe如何解决?

    1.首先,我们要确保电脑上已经安装了TortoiseSVN. 2.打开IDEA-File-Settings-Version Control-Subversion,在右边的界面上选择TortoiseSv ...

  8. 1012 The Best Rank (25分) vector与结构体排序

    1012 The Best Rank (25分)   To evaluate the performance of our first year CS majored students, we con ...

  9. Linux centos7 VMware MariaDB安装、Apache安装

    一.MariaDB安装 cd /usr/local/src 进入包放置目录 官网下载 wget http://mirrors.tuna.tsinghua.edu.cn/mariadb//mariadb ...

  10. AVL-Tree (平衡二叉树)

    看到网上AVL-Tree大多数都是用相同的实现方式 —— 递归进行插入.删除.维护平衡等,而我比较喜欢用带父指针的数据结构,于是想了一下午,用C实现了一个迭代版的. 由于没有暂时没有好的画二叉树的工具 ...