ASP.NET中各个后缀名的含义
1 .Global.asax
文件是 ASP.NET 应用程序的中心点。它提供无数的事件来处理不同的应用程序级任务,比如用户身份验证、应用程序启动以及处理用户会话等。你应该熟悉这个可选文件,这样就可以构建出健壮的ASP.NET 应用程序。
2 .sln:
解决方案文件,为解决方案资源管理器提供显示管理文件的图形接口所需的信息。
3 .csproj:
项目文件,创建应用程序所需的引用、数据连接、文件夹和文件的信息。
4 .aspx:
Web 窗体页由两部分组成:视觉元素(HTML、服务器控件和静态文本)和该页的编程逻辑。Visual Studio 将这两个组成部分分别存储在一个单独的文件中。视觉元素在.aspx 文件中创建。
5 .ascx:
ASP.NET的用户控件(也叫做“pagelets”),是作为一种封装了特定功能和行为(这两者要被用在Web应用程序的各种页面上)的Web页面被开发的。一个用户控件包含了HTML、代码和其他Web或者用户控件的组合,并在Web服务器上以自己的文件格式保存,其扩展名是*.ascx。ASP.NET里的缺省配置并不允许Web客户端通过URL来访问这些文件,但是这个网站的其他页面可以集成这些文件里所包含的功能。
6 .aspx.cs:
Web 窗体页的编程逻辑位于一个单独的类文件中,该文件称作代码隐藏类文件(.aspx.cs)。
7 .cs:
类模块代码文件。业务逻辑处理层的代码。
8 .asax:
Global.asax 文件(也叫做 ASP.NET 应用程序文件)是一个可选的文件,该文件包含响应 ASP.NET 或 HTTP 模块引发的应用程序级别事件的代码。
9 .config:
Web.config 文件向它们所在的目录和所有子目录提供配置信息。
10 .aspx.resx/.resx:
资源文件,资源是在逻辑上由应用程序部署的任何非可执行数据。通过在资源文件中存储数据,无需重新编译整个应用程序即可更改数据。
11 .XSD:
XML schema的一种.从DTD,XDR发展到XSD
12 .pdb:
PDB(程序数据库)文件保持着调试和项目状态信息,从而可以对程序的调试配置进行增量链接。
.suo:解决方案用户选项,记录所有将与解决方案建立关联的选项,以便在每次打开时,它都包含您所做的自定义设置。
13 .asmx:
asmx 文件包含 WebService 处理指令,并用作 XML Web services 的可寻址入口点
14 .vsdisco
(项目发现)文件 基于 XML 的文件,它包含为 Web 服务提供发现信息的资源的链接 (URL)。
15 .htc:
一个HTML文件,包含脚本和定义组件的一系列HTC特定元素.htc提供在脚本中implement组件的机制
C# 编码规范
1. 简介 3
2. 适用范围 3
3. 文体 3
4. 代码组织与风格 3
4.1. Tab 3
4.2. 缩进 4
4.3. 空行 4
4.4. 函数长度 4
4.5. {”,“}” 4
4.6. 行宽 4
4.7. 空格 4
5. 注释 5
5.1. 注释的基本约定 5
5.2. 注释类型 5
5.2.1. 块注释 5
5.2.2. 行注释 5
5.2.3. 尾随注释 5
5.3. 注释哪些部分 6
5.4. 程序修改注释 7
6. 命名 7
6.1. 命名的基本约定 7
6.2. 各种标示符类型的命名约定 9
6.2.1. 程序集命名 9
6.2.2. 命名空间命名 9
6.2.3. 类和接口命名 9
6.2.4. 方法命名 9
6.2.5. 变量命名 10
6.3. 组件名称缩写列表 10
7. 声明 11
8. 表达式和语句 12
9. 类型设计规范 14
9.1. 类型和命名空间 14
9.2. 类型和接口的选择 15
9.3. 抽象类设计: 15
9.4. 静态类设计 15
9.5. 枚举设计 16
10. 成员设计规范 17
10.1. 成员设计的一般规范 17
10.1.1. 方法的重载规范; 17
10.1.2. 属性和方法的选择 19
10.2. 属性的设计规范: 19
10.3. 构造函数的设计规范 20
10.4. 字段设计规范 20
10.5. 参数的设计规范 21
10.5.1. 参数设计中枚举和布尔参数的选择规范 21
10.5.2. 参数验证的规范: 22
10.5.3. 参数传递的规范: 22
11. 扩展性设计规范 22
12. 异常处理规范 23
12.1. 异常类型选择规范 23
12.2. 异常处理规范 23
12.3. 标准异常类的使用: 23
12.3.1. Exception与SystemException 23
12.3.2. InvalidOperationException 24
12.3.3. ArgumentException,ArgumentNullException,ArgumentOutOfRangeException 24
12.3.4. NullRefernceException,IndexOutOfRangeException,AccessViolationException 24
12.3.5. StackOverflowException: 24
12.3.6. OutOfMemoryException: 24
12.4. 自定义异常类型设计规则: 24
12.5. 异常与性能 24
13. 其他规定 24
14. 参考文档 25
1. 简介
本规范为一套编写高效可靠的 C# 代码的标准、约定和指南。它以安全可靠的软件工程原则为基础,使代码易于理解、维护和增强,提高生产效率。同时,将带来更大的一致性,使软件开发团队的效率明显提高。
2. 适用范围
本规范适用于公司所有的C#源代码,为详细设计,代码编写和代码审核提供参考和依据。
3. 文体
本规范中的建议分为四种:要,建议,避免,不要,表示需要遵循的级别。文档中会以粗体表示。对于应遵循的规范,前面会以“Ö”来表示,对不好的做法前面会以“´”来表示:
要:描述必须遵循的规范。例如:
Ö 异常类要以“Exception”做为后缀;
建议:描述在一般情况下应该遵循的规范,但如果完全理解规范背后的道理,并有很好的理由不遵循它时,也不畏惧打破常规。例如:
Ö 强制类型转换时,在类型和变量之间建议加一空格。
不要:描述一些几乎绝对绝不应该违反的规范。例如:
´ 每个函数有效代码(不包括注释和空行)长度不要超过50行。
避免:与建议相对,一般情况下应该遵循,但有很好的理由时也可以打破。例如:
´ 避免块内部的变量与它外部的变量名相同。
对一些规范内容一并提供了示例代码。
4. 代码组织与风格
4.1. Tab
Ö 要使一个Tab为4个空格长。
4.2. 缩进
Ö 要使一个代码块内的代码都统一缩进一个Tab长度。
4.3. 空行
Ö 建议适当的增加空行,来增加代码的可读性。
Ö 在在类,接口以及彼此之间要有两行空行:
Ö 在下列情况之间要有一行空行:
方法之间;
局部变量和它后边的语句之间;
方法内的功能逻辑部分之间;
4.4. 函数长度
´ 每个函数有效代码(不包括注释和空行)长度不要超过50行。
4.5. {”,“}”
Ö 开括号“{”要放在块的所有者的下一行,单起一行;
Ö 闭括号“}”要单独放在代码块的最后一行,单起一行。
4.6. 行宽
´ 每行代码和注释不要超过70个字符或屏幕的宽度,如超过则应换行,换行后的代码应该缩进一个Tab。
4.7. 空格
´ 括号和它里面的字符之间不要出现空格。括号应该和它前边的关键词留有空格,如:while (true) {};
´ 但是方法名和左括号之间不要有空格。
Ö 参数之间的逗号后要加一空格。如:method1(int i1, int i2)
Ö for语句里的表达式之间要加一空格。如:for (expr1; expr2; expr3)
Ö 二元操作符和操作数之间要用空格隔开。如:i + c;
Ö 强制类型转换时,在类型和变量之间要加一空格。如:(int) i ;
5. 注释
5.1. 注释的基本约定
Ö 注释应该增加代码的清晰度;
Ö 保持注释的简洁,不是任何代码都需要注释的,过多的注释反而会影响代码的可读性。
´ 注释不要包括其他的特殊字符。
Ö 建议先写注释,后写代码,注释和代码一起完成
Ö 如果语句块(比如循环和条件分枝的代码块)代码太长,嵌套太多,则在其结束“}”要加上注释,标志对应的开始语句。如果分支条件逻辑比较复杂,也要加上注释。
Ö 在VS2005环境中通过配置工程编译时输出XML文档文件可以检查注释的完整情况,如果注释不完整会报告编译警告;
5.2. 注释类型
5.2.1. 块注释
Ö 主要用来描述文件,类,方法,算法等,放在所描述对象的前边。具体格式以IDE编辑器输入“///”自动生成的格式为准,另外再附加我们自定义的格式,如下所列:
///
对类和接口的注释必须加上上述标记,对方法可以视情况考虑
5.2.2. 行注释
Ö 主要用在方法内部,对代码,变量,流程等进行说明。整个注释占据一行。
5.2.3. 尾随注释
Ö 与行注释功能相似,放在代码的同行,但是要与代码之间有足够的空间,便于分清。例:
int m = 4 ; // 注释
Ö 如果一个程序块内有多个尾随注释,每个注释的缩进要保持一致。
5.3. 注释哪些部分
项目 |
注释哪些部分 |
参数 |
参数用来做什么 任何约束或前提条件 |
字段/属性 |
字段描述 |
类 |
类的目的 已知的问题 类的开发/维护历史 |
接口 |
目的 它应如何被使用以及如何不被使用 |
局部变量 |
用处/目的 |
成员函数注释 |
成员函数做什么以及它为什么做这个 哪些参数必须传递给一个成员函数 成员函数返回什么 已知的问题 任何由某个成员函数抛出的异常 成员函数是如何改变对象的 包含任何修改代码的历史 如何在适当情况下调用成员函数的例子适用的前提条件和后置条件 |
成员函数内部注释 |
控制结构 代码做了些什么以及为什么这样做 局部变量 难或复杂的代码 处理顺序 |
5.4. 程序修改注释
Ö 新增代码行的前后要有注释行说明,对具体格式不作要求,但必须包含作者,新增时间,新增目的。在新增代码的最后必须加上结束标志;
Ö 删除代码行的前后要用注释行说明,删除代码用注释原有代码的方法。注释方法和内容同新增;删除的代码行建议用#region XXX #endregion 代码段折叠,保持代码文件干净整洁
Ö 修改代码行建议以删除代码行后再新增代码行的方式进行(针对别人的代码进行修改时,必须标明,对于自己的代码进行修改时,酌情进行)。注释方法和内容同新增;
6. 命名
6.1. 命名的基本约定
Ö 要使用可以准确说明变量/字段/类的完整的英文描述符,如firstName。对一些作用显而易见的变量可以采用简单的命名,如在循环里的递增(减)变量就可以被命名为 ” i ”。
Ö 要尽量采用项目所涉及领域的术语。
Ö 要采用大小写混合,提高名字的可读性。为区分一个标识符中的多个单词,把标识符中的每个单词的首字母大写。不采用下划线作分隔字符的写法。有两种适合的书写方法,适应于不同类型的标识符:
PasalCasing:标识符的第一个单词的字母大写;
camelCasing:标识符的第一个单词的字母小写。
下表描述了不同类型标识符的大小写规则:
标识符 |
大小写 |
示例 |
命名空间 |
Pascal |
namespace Com.Techstar.ProductionCenter |
类型 |
Pascal |
public class DevsList |
接口 |
Pascal |
public interface ITableModel |
方法 |
Pascal |
public void UpdateData() |
属性 |
Pascal |
Public int Length{…} |
事件 |
Pascal |
public event EventHandler Changed; |
私有字段 |
Camel |
private string fieldName; |
非私有字段 |
Pascal |
public string FieldName; |
枚举值 |
Pascal |
FileMode{Append} |
参数 |
Camel |
public void UpdateData(string fieldName) |
局部变量 |
Camel |
string fieldName; |
´ 避免使用缩写,如果一定要使用,就谨慎使用。同时,应该保留一个标准缩写的列表,并且在使用时保持一致。
Ö 对常见缩略词,两个字母的缩写要采用统一大小写的方式(示例:ioStream,getIOStream);多字母缩写采用首字母大写,其他字母小写的方式(示例:getHtmlTag);
´ 避免使用长名字(最好不超过 15 个字母)。
´ 避免使用相似或者仅在大小写上有区别的名字。
6.2. 各种标示符类型的命名约定
6.2.1. 程序集命名
Ö 公司域名(Techstar)+ 项目名称 + 模块名称(可选),例如:
中心系统程序集:Techstar.ProductionCenter;
中心系统业务逻辑程序集:Techstar. ProductionCenter.Business;
6.2.2. 命名空间命名
Ö 采用和程序集命名相同的方式:公司域名(Techstar)+ 项目名称 + 模块名称。 另外,一般情况下建议命名空间和目录结构相同。例如:
中心系统:Techstar.ProductionCenter;
中心系统下的用户控件:Techstar.ProductionCenter.UserControl;
中心系统业务逻辑:Techstar. ProductionCenter.Business;
中心系统数据访问:Techstar. ProductionCenter.Data;
6.2.3. 类和接口命名
Ö 类的名字要用名词;
´ 避免使用单词的缩写,除非它的缩写已经广为人知,如HTTP。
Ö 接口的名字要以字母I开头。保证对接口的标准实现名字只相差一个“I”前缀,例如对IComponent的标准实现为Component;
Ö 泛型类型参数的命名:命名要为T或者以T开头的描述性名字,例如:
public class List
public class MyClass
´ 对同一项目的不同命名空间中的类,命名避免重复。避免引用时的冲突和混淆;
6.2.4. 方法命名
Ö 第一个单词一般是动词
Ö 如果方法返回一个成员变量的值,方法名一般为Get+成员变量名,如若返回的值 是bool变量,一般以Is作为前缀。另外,如果必要,考虑用属性来替代方法,具 体建议见10.1.2节;
Ö 如果方法修改一个成员变量的值,方法名一般为:Set + 成员变量名。同上,考虑 用属性来替代方法;
6.2.5. 变量命名
Ö 按照使用范围来分,我们代码中的变量的基本上有以下几种类型,类的公有变量;类的私有变量(受保护同公有);方法的参数变量;方法内部使用的局部变量。这些变量的命名规则基本相同,见标识符大小写对照表。区别如下:
i. 类的公有变量按通常的方式命名,无特殊要求;
ii. 类的私有变量采用两种方式均可:采用加“m”前缀,例如mWorkerName;
iii. 方法的参数变量采用camalString,例如workerName;
iv. 方法内部的局部变量采用camalString,例如workerName;
´ 不要用_或&作为第一个字母;
Ö 尽量要使用短而且具有意义的单词;
Ö 单字符的变量名一般只用于生命期非常短暂的变量。i,j,k,m,n一般用于integer;c,d,e 一般用于characters;s用于string
Ö 如果变量是集合,则变量名要用复数。例如表格的行数,命名应为:RowsCount;
Ö 命名组件要采用匈牙利命名法,所有前缀均应遵循同一个组件名称缩写列表
6.3. 组件名称缩写列表
缩写的基本原则是取组件类名各单词的第一个字母,如果只有一个单词,则去掉其中的元音,留下辅音。缩写全部为小写。
组件类型 |
缩写 |
例子 |
Label |
Lbl |
lblNote |
TextBox |
Txt |
txtName |
Button |
Btn |
btnOK |
ImageButton |
Ib |
ibOK |
LinkButton |
Lb |
lbJump |
HyperLink |
Hl |
hlJump |
DropDownList |
Ddl |
ddlList |
CheckBox |
Cb |
cbChoice |
CheckBoxList |
Cbl |
cblGroup |
RadioButton |
Rb |
rbChoice |
RadioButtonList |
Rbl |
rblGroup |
Image |
Img |
imgBeauty |
Panel |
Pnl |
pnlTree |
TreeView |
Tv |
tvUnit |
WebComTable |
Wct |
wctBasic |
ImageDateTimeInput |
Dti |
dtiStart |
ComboBox |
Cb |
cbList |
MyImageButton |
Mib |
mibOK |
WebComm.TreeView |
Tv |
tvUnit |
PageBar |
Pb |
pbMaster |
7. 声明
Ö 每行要只有一个声明,如果是声明i,j,k之类的简单变量可以放在一行;
Ö 除了for循环外,声明要放在块的最开始部分。for循环中的变量声明可以放在for语句中。如:for(int i = 0; I < 10; i++) 。
´ 避免块内部的变量与它外部的变量名相同。
8. 表达式和语句
Ö 每行建议只有一条语句。
Ö if-else,if-elseif语句,任何情况下,都应该有“{”,“}”,格式如下:
if (condition)
{
statements;
}
else if (condition)
{
statements;
}
else
{
statements;
}
Ö for语句格式如下:
for (initialization; condition; update)
{
statements;
}
如果语句为空:
for (initialization; condition; update) ;
Ö while语句格式如下:
while (condition)
{
statements;
}
如果语句为空:
while (condition);
Ö do-while语句格式如下:
do
{
statements;
}
while (condition);
Ö switch语句,每个switch里都应包含default子语句,格式如下:
switch (condition)
{
case ABC:
statements;
/* falls through */
case DEF:
statements;
break;
case XYZ:
statements;
break;
default:
statements;
break;
}
Ö try-catch语句格式如下:
try
{
statements;
}
catch (ExceptionClass e)
{
statements;
}
finally
{
statements;
}
9. 类型设计规范
Ö 要确保每个类型由一组定义明确,相互关联的成员组成,而不仅仅是一些无关功能的随 机集合;
9.1. 类型和命名空间
Ö 要用命名空间把类型组织成相关域的层次结构。例如:
界面层:Techstar.ProductionCenter;
业务逻辑层:Techstar.ProductionCenter.Business;
数据访问层:Techstar.ProductionCenter.Data;
´ 避免过深的命名空间;
´ 避免太多的命名空间;
9.2. 类型和接口的选择
Ö 要优先采用类而不是接口。
接口的缺点在于语义变化时改变困难。注意接口并不是协定,把协定和实现分开并非一 定用接口实现,用基类和抽象类同样可以表达;
Ö 建议使用抽象类而不是接口来解除协定与实现间的偶合;
Ö 要定义接口,来实现类似多重继承的效果;
精心定义接口的标志是一个接口只做一件事情。关键是接口的协定需要保持不变, 如果一个接口包含太多功能,那么这个胖接口产生变化的机会就会大得多。
9.3. 抽象类设计:
´ 不要在抽象类中定义公有的或内部受保护的构造函数。因为抽象类无法实例化,所以这 种设计会误导用户;
Ö 要为抽象类定义受保护的构造函数或内部构造函数;
9.4. 静态类设计
静态类是一个只包含静态成员的类,它提供了一种纯面向对象设计和简单性之间的一个权衡,广泛用来提供类似于全局变量或一些通用功能。
Ö 要少用静态类。静态类应该仅用作辅助类;
´ 避免把静态类当作杂物箱。每个静态类都应该有其明确目的;
Ö 不要在静态类中声明或覆盖实例成员;
9.5. 枚举设计
Ö 要用枚举来加强那些表示值的集合的参数,属性以及返回值的类型性;
Ö 要优先使用枚举而不是静态常量。例如:
//不好的写法
public static class Color
{
public static int Red = 0;
public static int Green = 1;
public static int Blue = 2;
}
//好的写法
public enum Color
{
Red,
Green,
Blue
}
´ 不要把枚举用于开放的场合,例如操作系统的版本,朋友的名字等;
´ 枚举最后一个值不要加逗号;
´ 枚举中不要提供为了今后使用而保留的枚举值;
10. 成员设计规范
方法,属性,事件,构造函数以及字段等统称为成员。
10.1. 成员设计的一般规范
10.2. 方法的重载规范;
´ 避免在重载中随意的给参数命名。如果两个重载中的某个参数表示相同的输入,那么该参数的名字应该相同。例如:
public class String
{
//好的写法
public int IndexOf(string value) { ...}
public int IndexOf(string value, int startIndex) { ...}
//不好的写法
public int IndexOf(string value) { ...}
public int IndexOf(string str, int startIndex) { ...}
}
´ 避免使重载成员的参数顺序不一致。在所有的重载中,同名参数应该出现在相同的位置。 例如:
public class EventLog
{
public EventLog();
public EventLog(string logName);
public EventLog(string logName, string machineName);
public EventLog(string logName, string machineName, string source);
}
Ö 较短的重载应该仅仅调用较长的来实现。另外,重载如果需要扩展性,把最长重载 做成虚函数。例如:
public class String
{
public int IndexOf(string s)
{
//调用
return IndexOf(s, 0);
}
public int IndexOf(string s, int startIndex)
{
//调用
return IndexOf(s, startIndex, s.Length);
}
public virtual int IndexOf(string s, int startIndex, int Count)
{
//实际的代码
}
}
Ö 要允许可选参选为null。这样做是为了避免调用者调用之前需要检查参数是否null。例 如:
//允许为null时的调用
DrawGeometry(brush, pen, geometry);
//不允许为null时的调用
if (geometry == null) DrawGeometry(brush, pen);
else DrawGeometry(brush, pen, geometry);
10.3. 属性和方法的选择
Ö 基本原则是方法表示操作,属性表示数据。如果其他各方面都一样,优先使用属性而不 是方法。
Ö 要使用属性,如果该成员表示类型的逻辑attribue
Ö 如果属性的值存储在内存中,而提供属性的目的仅仅是为了访问该值,要使用属性而不 要使用方法
Ö 如果该操作每次返回的结果不同,那么要使用方法。例如来自于.net framework的例子:
//好的写法
Guid.NewGuid();
//不好的写法
DateTime.Now;
Ö 如果该操作比访问字段慢一个或多个数量级,要使用方法。
Ö 如果该操作有严重的副作用,要使用方法。
10.4. 属性的设计规范:
Ö 如果不应该让调用方法改变属性值,要创建只读属性;
´ 不要提供只写属性;
Ö 要为所有的属性提供合理的默认值,这样可以确保默认值不会导致漏洞或效率低的代 码;
Ö 要允许用户以任何顺序来设置属性的值;
Ö 避免在属性的获取方法抛出异常。
属性的获取方法应该是个简单的操作,不应该有任何的条件。如果一个获取方法会抛出 异常,按么可能它更应该设计为方法。
10.5. 构造函数的设计规范
Ö 建议提供简单的构造函数,最好是默认构造函数。简单的构造函数增强易用性;
Ö 考虑扩展性,如果构造函数设计的不自然,建议用静态的工厂方法来替代构造函数;
Ö 要把构造函数的参数用作设置主要属性的便捷方法。如果构造函数参数仅用来设置属 性,应和属性名称相同。仅有大小写的区别;
Ö 要在构造函数中做最少的工作。任何其他处理应该推迟到需要的时候;
Ö 要在类中显示的声明公用的默认构造函数,如果这样的构造函数是必须的。
如果没有显示默认构造函数,填加有参数构造函数时往往会破坏已有使用默认构造函数 的代码;
´ 避免在对象的构造函数内部调用虚成员。这样在扩展设计的时候会导致难以理解的现 象;
10.6. 字段设计规范
´ 不要提供公有的或受保护的字段。代之以属性来访问字段;
Ö 要只用常量字段来表示永远不会改变的量。否则会导致兼容性问题。下面是正确的例子:
public struct Int32
{
public const int MaxValue = 0x7fffffff;
public const int MinValue = unchecked((int)0x80000000);
}
Ö 要用公有的静态只读字段来定义预定义的对象实例。例如:
public struct Color
{
public static readonly Color Red = new Color(0x0000FF);
}
10.7. 参数的设计规范
Ö 要用类结构层次中最接近基类类型来作为参数的类型,同时要保证该类型能够提供成员 所需的功能。例如:
要设计一个集合遍历的方法,那么参数应该是IEnbumerable为参数,而不应该是IList, 这样方法具有更强的适应性。
´ 不要使用保留参数。如果将来需要更多的参数,那么可以增加重载成员。例如:
//不好的写法
public void Method(string reserved, SomeOption option);
//好的写法
public void Method(SomeOption option);
//将来填加
public void Method(SomeOption option, string path);
10.7.1. 参数设计中枚举和布尔参数的选择规范
Ö 要用枚举。在代码阅读,书写中,枚举都比布尔的可读性好很多。例如:
//使用布尔型,阅读的时候不会轻易了解参数的含义
FileStream f = File.Open(“1.txt”, true, false);
//使用枚举型
FileStream f = File.Open(“1.txt”,CasingOptions.CaseSenstive, FileMode.Open);
´ 不要使用布尔参数,除非百分之百肯定绝对不需要两个以上的值。即使此时,采用枚举 往往也可以提供更好的可读性,如上例。
Ö 考虑在构造函数中,对确实只有两种状态值的参数以及用来初始化布尔属性的参数使用 布尔类型;
10.7.2. 参数验证的规范:
Ö 要验证传给公有的,受保护的或显示成员的参数是否合法。如果验证失败,应该抛出 System.ArgutmentException或其子类;
Ö 要抛出System.ArgutmentNullException,如果传入的null,而该成员不支持null;
10.7.3. 参数传递的规范:
´ 避免使用输出参数或引用参数;
11. 扩展性设计规范
´ 如果没有恰当理由,不要把类密封起来。这些理由包括:
A)类为静态类;
B)类的受保护成员保存了高度机密信息;
C)类继承了许多虚成员,逐个密封的代价太高,不如密封整个类;
D)不要在密封类中声明保护成员或虚成员,因为无法覆盖其实现;
Ö 建议用保护成员用于高级定制。它提供了扩展性,同时也避免了公用接口过于复杂;
´ 不要使用虚成员,除非有合适的理由;
Ö 建议只有在绝对必须的时候才用虚成员提供扩展性,并使用Template Method模式;
Ö 要优先使用受保护的虚成员,而不是公有虚成员。公有成员通用调用受保护的虚成员的方式来提供扩展性;
12. 异常处理规范
Ö 异常的思想是只对错误采用异常处理:逻辑和编程错误,设置错误,被破坏的数据,资源耗尽,等等。通常的法则是系统在正常状态下以及无重载和硬件失效状态下,不应产生任何异常。异常处理时可以采用适当的日志机制来报告异常,包括异常发生的时刻;
´ 一般情况下不要使用异常实现来控制程序流程结构;
´ 使用异常而不要用错误代码来报告错误;
Ö 要通过抛出异常的方式来报告操作失败。如果成员无法成功地完成它应该做的任务,那么应该抛出异常;
12.1. 异常类型选择规范
Ö 优先考虑使用System命名空间中已有的异常,而不是自己创建新的异常类型;
Ö 要使用最合理,最具针对性的异常。例如,对参数为空,应抛出 System.ArgutmentNullException,而不是System.ArgutmentException
12.2. 异常处理规范
´ 不是百分之百确定的情况,不要吞掉异常;
Ö 建议捕获特定类型的异常,如果理解该异常在具体环境当中产生的原因;
´ 不要捕获不应该捕获的异常,通常应该允许异常沿着调用栈传递;
Ö 进行清理工作时要用try-finally,避免使用try-catch;
Ö 要在捕获并重新抛出异常时使用空的throw语句,这是保持调用栈的最好方法
12.3. 标准异常类的使用:
12.3.1. Exception与SystemException
´ 不要抛出这两种类型的异常;
´ 避免捕获这两种异常,除非是在顶层的异常处理器中;
12.3.2. InvalidOperationException
Ö 对象处于不正确状态时抛出;
12.3.3. ArgumentException,ArgumentNullException,ArgumentOutOfRangeException
Ö 如果传入的是无效参数,要抛出参数异常,尽可能使用位于继承层次末尾的类型;
Ö 要在抛出异常时设置ParaName属性;
12.3.4. NullRefernceException,IndexOutOfRangeException,AccessViolationException
´ 不要显示抛出或捕获;
12.3.5. StackOverflowException:
´ 不要显示抛出或捕获;
12.3.6. OutOfMemoryException:
´ 不要显示抛出或捕获;
12.4. 自定义异常类型设计规则:
´ 避免太深的继承层次;
Ö 要从已有的异常基类继承;
Ö 异常类要以“Exception”做为后缀;
Ö 要使异常可序列化,使其能跨应用程序域和远程边界仍能正常使用;
Ö 要把与安全性有关的信息保存在私有的异常状态中
12.5. 异常与性能
Ö 如果在普通场景都会抛出异常,要采用先效验合法性的方式来避免抛出异常引起的性能 问题;
13. 其他规定
Ö 为避免频繁改动代码,代码中只写比较简单的和不会经常发生变化的SQL,如果SQL 经常发生变化或是比较复杂,存到SysMisc中,比如统计用到的SQL;
Ö 在VS2005开发环境中,采用代码分析工具来做自动化的代码分析,以保证代码质量, 具体的使用建议如下:
A)启用代码分析,并设置当风格不符合要求时为错误而不是警告;
B)如果不是做代码审核,此开关应关闭。加上了这个选项的时候编译很慢;
C)详设的时候打开开关,检查详设是否符合编程规范;
D)所有的选项都应当打开。以下内容需要单独设置:
编码 |
名称 |
大类 |
建议 |
使用等级 |
CA2209 |
程序集应声明最小安全性 |
用法规则 |
不建议使用 |
警告 |
CA1814 |
与多维数组相比,首选使用交错的数组 |
性能规则 |
使用,但降低等级 |
警告 |
CA1822 |
将成员标记为 static |
性能规则 |
较繁锁,且影响代码质量 |
禁用 |
CA2210 |
程序集应具有有效的强名称 |
设计规则 |
影响Xcopy部署 |
禁用 |
CA1302 |
不要对区域设置特定的字符串进行硬编码 |
全球化规则 |
很繁琐,并且工具支持的不好。全球化规则全部禁用 |
禁用 |
CA2100 |
检查 Sql 查询中是否有安全漏洞 |
安全性规则 |
都采用参数化查询,有可能会参数过长;如果是内部参数,也不会有安全问题 |
警告 |
14. 参考文档
1,《.NET设计规范》,本规范很多内容都参考了这本书,书中对规范背后的背景和原则做了深入讨论;
dotNet平台主要开发技术总结
自微软2000年发布.Net战略以来有10年多,世界上有数百万的程序员在.Net Framework上构建了自己的应用产品。从2002年发布.Net1.0开始,先后发布了.Net1.0、1.1、2.0、3.5、4.0等重要版本。与之同时,微软也同时推出了集成IDE开发环境Visual Studio,目前最新版本是Visual Studio 2010。同时微软在VS2005引入了软件生命周期过程管理工具Visual Studio Team System(VSTS),扩展了Visual Studio的功能,提供了单元测试及代码分析工具,为项目经理、架构师、测试人员等角色都提供了相应的管理工具,使整个团队的软件开发的过程能够清晰可见。
结合本人.net的一些认识,下面简单总结一下在.Net平台使用的一些核心技术及组件。
通过在Windows内核操作系统之上创建了一个虚拟框架,使得开发者不需要考虑程序运行时CPU或其他硬件特性,封装了内核API以及一些核心类库及公用组件。这个环境又称为公用语言运行时(CLR)。我们编写.Net的程序需要在.Net framework之上来运行,又称为托管应用程序。CLR还实现了安全、异常管理,以及在C++时代令人头疼的内存管理问题。
· ADO.Net:提供了统一的数据访问模型,实现对数据的CRUD操作。包括了对Access访问的OLEDB Provider、开放数据连接ODBC的ODBC .Net Data Provider、SQL SERVER访问的SQLServer Provider以及Oracle访问的Oracle Provider等。
微软也提供了开源的Enterprice Library封装了数据访问类,简化了很多常见的数据访问任务,如读取显示数据,增删除改查,以及事务管理,并且对不同的数据源使用工厂模型提供了统一的数据库编程模型。
· ADO.Net Data Services Framework:提供了基于http的RESTful风格的Web Service,用来访问实体数据模型。使用URL统一资源路径来访问数据,可提供纯Atom格式或JSON格式的数据返回。
· ADO.Net Entity Framework:微软的O/RM解决方案。早期有开源的NHibernate框架,微软迟迟未加入,直到.Net Framework 3.5 SP1,目前版本Entity Framework 4.1。Entity Framework 利用了抽象化数据结构的方式,将每个数据库对象都转换成应用程序对象(entity),而数据字段都转换为属性(property),关系则转换为结合属性(association),让数据库的 E/R 模型完全的转成对象模型。EF将关系表的物理结构转化为精确反映通用业务对象的概念模型,让开发人员更容易理解业务并集中以对象的模型操作业务数据。
· ADO.Net Sync Framework:ADO.Net提供的同步服务,使用此框架我们可以使用一致的方式在应用、设备、服务之间同步数据。前提是数据库双方都要支持Ado.net,支持间歇性连接。
· LINQ:.Net 3.0引入在C#中以查询数据库TSQL相同的方式操作内存数据。包括:LINQ TO Objects、LINQ to XML、LINQ to SQL、LINQ to DataSet、LINQ to Entities以及LINQ to Data Servies。其中微软放弃了LINQ to SQL,已在.Net 4.0中被ADO.Net Entity Framework取代。
· SQL Server:重量级关系数据库引擎,自SQL SERVER 2005以来,加入了更多如数据库镜像等高级特性,性能及稳定性有了很大的改善。目前版本SQL SERVER 2008 R2。SQL SERVER不仅提供了关系数据库引擎,SQL 2005之后还集成SSIS集成服务,SSRS报表服务,提供BI(SSAS)等商业智能组件。
· WCF:.Net3.0引入的重要组件,WCF统一了数据通讯模型,使用一种可管理的方式来进行分布式通讯,并提供了良好的互操作性、安全机制。WCF整合了Enterprise Services、System.Messaging、Microsoft .NET Remoting、ASMX和Web Services Extensions (WSE)等通讯模型,使用单一的模型来处理不同类型的应用程序行为,显著降低应用程序开发的复杂性。 在.Net2008正式发布之后,本人带领团队基于.Net 3.5+WCF构建了一个大型的分布式应用系统,其良好的互操作性以及不同通讯协议统一的编程模型,大大降低了数据通讯开发的复杂度,提高了团队开发效率。并且提供了事务、日志监控机制,以及良好的安全特性。
· Asp.net Web Service:提供了一种简单的方式,发布Web服务来解决分布式计算与数据通讯需求,仅支持http协议。
· WF: .Net3.0引入的重要组件,它并不是一个像SQL Server这样可以直接用来执行业务流程的产品,而是一个用于开发工作流的基础组件。我们可以用它来开发顺序或基于状态机的工作流。
· Workflow Service:基于WCF服务提供的工作流服务,是将WCF进行扩展,整合了WCF及WF,将工作流以服务的形式提供出来并可被调用。
· MOSS:即SharePoint Services。MOSS是一个内容管理及协作平台,并提供基于WF引擎的工作流服务。可以使用Sharepoint Designer或VS中的Windows workflow designer来创建工作流,也可以直接用VisualStudio手工基于WF开发工作流跑在MOSS服务上。
· BizTalk Server: MS的重量级企业服务器产品,BizTalk主要面向业务流程,来设计和规划低耦合的业务流程。功能包括业务流程自动化,业务流程管理,企业应用集成以及企业之间的集成。通过BizTalk创建业务流程,可以将各种分散的应用程序融为一体利用图形用户界面来创建和修改业务流程。
· Asp.net:通过.Net创建浏览器应用,提供标准用户界面及窗体设计,通过IIS进行托管。
· AJax: 使用Ajax解决asp.net与客户端之间的异步请求,提升应用程序的响应,改善用户体验,避免过多的Postback。
· Jquery: jQuery是一套优秀的Javascript脚本库,对主流浏览器提供了良好的兼容性。是一个轻量级的js库(压缩后只有21k) 但不是框架。VS2008 SP1以及VS2010创建Web应用程序时,自动给你的项目添加Scripts/jquery_1.x.x.js脚本。 jQuery使用户能更方便地处理HTML documents、events、实现丰富的UI及动画效果,能方便地使用AJAX技术进行交互。安装VS2008 SP1后以及KB958502补丁,就可以在集成开发环境中使用Jquery并且有智能感知特性。
· Asp.net MVC: 通过使用MVC模式(模式-视图-控制器)创建ASP.NET应用程序,支持测试驱动开发。使用MVC可以将用户显示界面(视图)从业务逻辑(控制器)中分离出来,提高了代码的重用性与可读性,将数据(模型)从对其操作的逻辑(控制器)分离出来可以设计一个与后台数据无关的系统。在iPhone应用程序开发,大量应用了MVC模式。
· Silverlight: WPF的一个子集,为跨浏览器及跨操作系统平台而设计。是微软应对RIA策略的举措(直接对手是Flash),以浏览器的外挂组件方式(Silverlight4插件大约5~6M),在Web程序中能提供良好的用户交互与体验,以及流媒体应用等前端解决方案。Silverlight封装了.Net的一些基础组件(包括WCF/LINQ等一些高级特性),直接以.net framework编程模型来开发应用程序。Silverlight使用XMAL标记来描述UI界面,并且为设计人员提供了Expression Blend工具,实现了开发与设计良好的职责分工。但是在HTML5标准发布后,各大厂商包括微软都在积极拥抱HTML5,特别是微软PDC2010大会上发布“微软的战略已经改变”,先后出现了各种担优的声音。微软又先后在2010 Silverlight Firestarter发布会上发布了Silverlight 5特性,以及在2011 Build大会前发布了Silverlight 5 RC版本,证明微软将继续支持并发展Silverlight浏览器插件技术。此外在Windows Phone 7中也是应用Silverlight技术来开发WP7应用。个人看来,HTML5毕竟是大趋势,各大厂商以及W3C标准,跨平台的互联网应用HTML5是最佳选择, 但Siverlight仍会在企业内部(Intranet)应用中发挥重要价值。我公司使用的一套内部应用系统,就是基于Silverlight技术创建。在HTML5还有很长的路要走,在其成熟前,Silverlight提供了快速的.net原生开发,以及像Winform一样良好的用户操作与界面响应能力。
· Web服务器-IIS: 通过IIS提供Internet上的web应用托管,包括基于http请求的www服务,以及ftp服务。另外使用SSL能提供http通讯的数据加密。IIS7.0微软重新设计,提供了重大功能及性能改进。
· Windows Form: Win32时代最经典的标准用户界面。比较适合开发一些交互性很强,界面复杂,实例程序以及一些本地化应用。对于企业应用缺点是传统的C/S程序安装部署比较麻烦,可以使用Click Once技术及自动升级安装部署的方式解决。
· WPF: 如果要展现更高级漂亮的用户界面、展现灵活多变的动画效果以及基于流媒体、向量图形的应用,使用WPF是最佳选择。WPF是.Net3.0框架加入的重要组件,使用标准的XML语言描述界面布局(被称为XAML语言),支持数据绑定及事件定义。WPF可以直接部署在安装有.Net framework的桌面上(C/S),也可以运行在支持XBAP的浏览器内(B/S)。 WPF使得在开发程序时,通过分离UI与逻辑层,更易分工(如让美工人员进行专业的UI界面设计)。 另外专为UI设计人员提供了Expression Blend工具。
· .Net Compact Framework: 在WindowsMobile上的创建的一个.Net framework子集,用来设计移动应用程序。不过在有限的CPU与内存资源下,系统运行效率并不是太高。此外微软已彻底放弃WindowsMobile,相信.NET Compact Framework3.7是最后一个版本。
· WP7: 面对移动失利的市场,WindowsMobile迟迟未见改进,直到去年微软正式发布了WindowsPhone7,但销量不佳,今年微软也与Nokia宣布深度合作。微软本周在台湾地区先行发布了WindowsPhone 7.5芒果的推送更新,但估计在Nokia大量发布新手机之前市场占有率很难有起色。其实个人更看好三星以及HTC的硬件及其创新能力,微软早就应与HTC等深度合作。 HTC曾是微软早期WindowsMobile的最有力的合作伙伴,记得在04、05年多普达手机占居了高端用户群,本人也一直使用过多款HTC手机。 如今Android与iPhone已占领绝大多数智能机市场,WP7的压力确实不小。 微软发布了免费的Visual Studio Express版本以及Windows Phone 7 SDK 来开发WP7应用。在WP7中可以使用Silverlight及XNA 2套框架分别开发WP7应用系统及游戏程序。WP7的XNA框架可以与微软的XBOX游戏兼容。 WP7中使用标准的Metro界面风格来创建应用。(说实话个人并不喜欢,色块很大并不友好,Title字体太大并且切割在不同的屏幕中)
Visual Studio Tools for Office,也是VBA的替代品。利用VisualStudio创建基于 Microsoft Office System 的应用,扩展增强Office的文件共享、协作、权限管理、数字分析、图表、电子邮件、日历等强大功能。
在前几天微软2011 Build大会上,微软发布了Windows8开发人员预览版。微软在应对iPad/iPhone居大成功压力下做出了重大举动,改变从Windows NT时代以来的仅以Win32 API为内核的框架,引入全部的WinRT API。WinRT将是Windows 8以Metro UI风格下核心API组件,它不是另一个抽象层,就像 Win32 API 一样,直接驻留在OS内核之上。WinRT API 从设计之初就是面向对象的,提供一致性、易用性、以及高性能特性。WinRT API 中支持C++、C#及VB,甚至JavaScript都可以直接调用WinRT底层API。虽然在Windows8中传统的UI仍可使用,但无疑Metro界面将是微软未来Windows8的主流。
作者: spring yang 来源: 博客园 发布时间: 2011-09-22 10:23 阅读: 1740 次 原文链接 全屏阅读 [收藏]
摘要:本文介绍的是C#开发中公共语言运行库(CLR),这些原理性质的知识能让大家更好的开发C#程序。
概述
.NET Framework的核心是其运行库的执行环境,称为公共语言运行库(CLR)或.NET运行库。通常将在CLR的控制下运行的代码称为托管代码(managed code)。
但是,在CLR执行编写好的源代码之前,需要编译它们(在C#中或其它语言中)。在.NET中,编译分为两个阶段:
1、把源代码编译为Microsoft中间语言(IL)。
2、CLR把IL编译为平台专用的代码。
这个两阶段的编译过程非常重要,因为Microsoft中间语言(托管代码)是提供.NET的许多优点的关键.
.NET平台的整体结构:
.NET Framework是架构在Windows平台上的一个虚拟的运行平台,你可以想象将最下层Windows换做其他的操作系统,例如说Linux, 一样可以实现使用符合CLS(Common Language Specification, 通用语言规范)的.NET语言(VB.NET、C#、JScript.NET等)来创建ASP.NET或Windows Form(可能会叫Linux Forms)应用程序的功能,这其实就是Mono计划要实现的功能。所以可以这么认为,理论上,C#是一种可以跨平台的语言,这很象Java。
C#另一个比较象Java的地方是,它也是一种(特殊意义上的)语言,同Java一样,C#编写的程序代码也是先通过C#编译器编译为一种特殊的字节代码 (Microsoft Intermediate Language, MSIL,微软中间语言),运行时再经由特定的编译器(JIT编译器)编译为机器代码,以供操作系统执行。
不仅是C#语言,所有.NET语言(将会包括我们常用的几十种现代的编码语言)都可以编写面向CLR的程序代码,这种代码在.NET中被称为托管代码(Managed Code),所有的Managed Code都直接运行在CLR上,具有与平台无关的特性。
解释性的语言很安全,并且可以通过他的运行平台为其赋予更多的功能,例如自动内存管理,异常处理等。
CLR结构图
C#所具有的许多特点都是由CLR提供的,如类型安全(Type Checker)、垃圾回收(Garbage Collector)、异常处理(Exception Manager)、向下兼容(COM Marshaler)等,具体的说,.NET上的CLR为开发者提供如下的服务:
1、平台无关:CLR实际上是提供了一项使用了虚拟机技术的产品,它构架在操作系统之上,并不要求程序的运行平台是 Windows系统,只要是能够支持它的运行库的系统,都可以在上面运行.NET应用。所以,一个完全由托管代码组成的应用程序,只要编译一次,就可以在任何支持.NET的平台上运行。
2、跨语言集成:CLR允许以任何语言进行开发,用这些语言开发的代码,可以在CLR环境下紧密无缝的进行交叉调用,例如,可以用VB声明一个基类对象,然后在C#代码中直接创建次基类的派生类。
3、自动内存管理:CLR提供了垃圾收集机制,可以自动管理内存。当对象或变量的生命周期结速后,CLR会自动释放他们所占用的内存.
4、跨语言应用
当编程人员在用自己喜欢的编程语言写源代码的时候, 这个源代码在被转化成媒介语言(IL)之前,先被编译成了一个独立的可执行单元(PE)。这样无论你是一个VB.NET程序员,或一个C#程序员,甚至是使用托管的C++的程序员。只要被编译成IL就是同等的。 首先,编译输出的exe是一个由中间语言(IL),元数据(Metadata)和一个额外的被编译器添加的目标平台的标准可执行文件头(比如Win32平台就是加了一个标准Win32可执行文件头)组成的PE(portable executable,可移植执行体)文件,而不是传统的二进制可执行文件 —— 虽然他们有着相同的扩展名。
中间语言是一组独立于CPU的指令集,它可以被即时编译器Jitter翻译成目标平台的本地代码。中间语言代码使得所有Microsoft.NET平台的高级语言C#, VB.NET, VC.NET等得以平台独立,以及语言之间实现互操作。元数据是一个内嵌于PE文件的表的集合。
5、版本控制
由于使用了元数据,所以你可以使用XCOPY简单的复制就可以了,而CLR也可以在运行时期读取元数据,以确保多版本程序运行在同一进程中。使用公共语言运行库的程序集的所有版本控制都在程序集级别上进行。一个程序集的特定版本和依赖程序集的版本在该程序集的清单中记录下来。除非被配置文件(应用程序配置文件、发行者策略文件和计算机的管理员配置文件)中的显式版本策略重写,否则运行库的默认版本策略是,应用程序只与它们生成和测试时所用的程序集版本一起运行。
6、.NET安全
.NET提供了一组安全方案。负责进行代码的访问安全性检查。允许我们对保护资源和操作的访问。代码需要经过身份确认和出处鉴别后才能得到不同程度的信任。安全策略是一组可配置的规则,公共语言运行库在决定允许代码执行的操作时遵循此规则。安全策略由管理员设置,并由运行库强制。
运行库确保代码只能访问安全策略允许的资源和调用安全策略允许的代码。 每当发生加载程序集的尝试时,运行库就使用安全策略确定授予程序集的权限。在检查了描述程序集标识的信息(称为证据)后,运行库使用安全策略决定代码的信任程度和由此授予程序集的权限。证据包括但不仅限于代码的出版商、它的站点以及它的区域。安全策略还确定授予应用程序域的权限。
7、简单的组件互操作性。
8、自描述组件:自描述组件是指将所有数据和代码都放在一个文件中的执行文件。自描诉组件可以大大简化系统的开发和配置,并且改进系统的可靠性。
通用语言运行时(CommonLanguageRuntiome, CLR)最早被称为下一代Windows服务运行时(NGWS Runtime)。它是直接建立在操作系统上的一个虚拟环境,主要的任务是管理代码的运行。CLR现在支持几十种现代的编程语言为它编写代码,然后以一种中间语言(Intermediate Langeoage, IL)代码的形成被执行。并且,CLR还提供了许多功能以简化代码的开发和应用配置,同时也改善了应用程序的可靠性。如你所知,如果某种语言的编译器是以运行时为目标的,那么利用该语言开发生成的代码在.NET中被称为托管代码,因为这样的代码是直接运行在CLR上的,所以具有与平台无关的特点。
在.NET平台结构图中,CLR的上面是.NET的基类库,这组基类库包括从基本输入输出到数据访问等各方面,提供了一个统一的面向对象的,层次化的,可扩展的编程接口。从.NET平台结构图中也可以看到,基类库可以被各种语言调用和扩展,也就是说不管是C#,VB.NET还是VC++.NET,都可以自由的调用.NET的类库,因为C#自身只有77个关键字,而且语法对程序员来说无需费工夫学习。 BCL则相反,它包含了4500个以上的类和无数的方法、属性,在你的C#程序中随时都可能会用到它来完成自己的任务。
还有一个很重要的概念你需要明白,这就是公共语言架构(Common Language Infrastructure, CLI). CLI是CLR的一个子集,也就是.NET中最终对编译成MSIL代码的应用程序的运行环境进行管理的那一部分。在CLR结构图中CLI位于下半部分,主要包括类加载器(Class Loader)、实时编译器(IL To Native Compilers)和一个运行时环境的垃圾收集及将使用任何语言编写的代码,通过其特定的编译器转换为MSIL代码之后运行其上,甚至还可以自己写 MSIL在CLI上运行。
9、调用和配置
当运行库试图解析对另一个程序集的引用时,就开始进行定位并绑定到程序集的进程。该引用可以是静态的,也可以是动态的。在生成时,编译器在程序集清单的元数据中记录静态引用。动态引用是由于调用各种方法而动态构造的,例如 System.Reflection.Assembly.Load 方法。 引用程序集的首选方式就是使用完全引用,包括程序集名称、版本、区域性和公钥标记(如果存在)。
运行库就会使用这些信息来定位程序集。无论是对静态程序集的引用还是对动态程序集的引用,运行库均使用相同的解析过程。 还可通过向调用方法仅提供有关程序集的部分信息的方式(例如仅指定程序集名称),对程序集进行动态引用。在这种情况下,仅在应用程序目录下搜索程序集,不进行其他检查。您可以使用不同加载程序集方法中的任何方法(例如 System.Reflection.Assembly.Load 或 AppDomain.Load)进行部分引用。如果希望运行库在全局程序集缓存和应用程序目录下检查引用的程序集,可以用 System.Reflection.Assembly.LoadWithPartialName 方法指定部分引用。
最后,可以使用诸如 System.Reflection.Assembly.Load 之类的方法进行动态引用并只提供部分信息;然后在应用程序配置文件中用
10、GC
一个跟踪过程,它传递性地跟踪指向当前使用的对象的所有指针,以便找到可以引用的所有对象,然后重新使用在此跟踪过程中未找到的任何堆内存。公共语言运行库垃圾回收器还压缩使用中的内存,以缩小堆所需要的工作空间。 垃圾收集器的基本算法很简单: ● 将所有的托管内存标记为垃圾 ● 寻找正被使用的内存块,并将他们标记为有效 ● 释放所有没有被使用的内存块 ● 整理堆以减少碎片。
CLR的基本特性
1、与本机代码无关 - MSIL (中间语言)
2、让我们使用同一种语言 - CLR (公共语言运行时)
3、我们手中的零件 - Assembly (装配件)
4、让我们在同一个系统中运行 - CTS (通用类型系统)
5、宇宙大爆炸后的产物 - metadata (元数据)
6、让我们的语言可以交流 - CLS (公共语言系统)
7、在动态中交互 - Reflection (反射)
8、属于我们自己的空间 - NameSpace (名称空间)
MSIL:微软中间语言 |
Reflection:反射 |
Metadata:元数据 |
PE:可执行可移植文件 |
Assembly: 程序集(装配件) |
NameSpace:名称空间 |
CTS:通用类型系统 |
GC(Garbage Colection) :无用单元回收 |
CLR:公共语言系统 |
Attribute:属性(注意不要和Property混淆) |
Boxing: 装箱 |
UnBoxing: 拆箱 |
MSIL 使用.NET支持的语言所编写的代码
MSIL(Microsoft Intermediate Language)微软的中间语言。和JAVA的虚拟机类似,是与CPU无关的指令集。当编译为托管代码时,编译器将源代码翻译为MSIL, 如上图所示。MSIL包括用于加载、存储和初始化对象以及对对象调用方法的指令,还包括用于算术和逻辑运算、控制流、直接内存访问、异常处理和其他操作的指令。在可以执行代码前,必须将 MSIL 转换为 CPU 特定的代码,这通常是通过实时 (JIT) 编译器完成的。由于公共语言运行库为它支持的每种计算机结构都提供了一种或多种 JIT 编译器,因此可以在任何受支持的结构上对同一组 MSIL 进行 JIT 编译和执行。这样总结上面的就是:中间语言是一组独立于CPU的指令集,它可以被即时编译器Jitter翻译成目标平台的本地代码。
PE
Windows PE和一个 .NET PE的主要区别在于Windows PE是由操作系统执行的,而 .NET PE 却被转变成为.NET Framework的CLR. 识别一个PE是 .NET还是Windows取决于他的通用的目标文件格式 (COFF) 是否使用Windows的操作系统。目标文件格式 (COFF) 指定了任何文件都分成两个部分:文件数据本身以及描述文件内包含的数据内容的头文件串。MSIL 汇编程序从 MSIL 汇编语言生成可移植可执行的 (PE) 文件。可以运行结果可执行文件(该文件包含 MSIL 和所需的元数据)以确定 MSIL 是否按预期执行。这就是我为什么会谈到PE。
那么PE文件是怎么执行的呢?下面是一个典型的.NET应用程序的执行过程:
1. 用户执行编译器输出的应用程序(PE文件),操作系统载入PE文件,以及其他的DLL(.NET动态连接库)。
2. 操作系统装载器根据PE文件中的可执行文件头跳转到程序的入口点。显然,操作系统并不能执行中间语言,该入口点也被设计为跳转到mscoree.dll(.NET平台的核心支持DLL)的_CorExeMain()函数入口。
3. CorExeMain()函数开始执行PE文件中的中间语言代码。这里的执行的意思是CLR(通用语言运行时)按照调用的对象方法为单位,用JIT(即时编译器)将中间语言编译成本地机二进制代码,执行并根据需要存于机器缓存。
4. 程序的执行过程中,GC(垃圾收集器)负责内存的分配,释放等管理功能。
5. 程序执行完毕,操作系统卸载应用程序。
.NET Framework 环境
下面的插图显示公共语言运行时和类库与应用程序之间以及与整个系统之间的关系。该插图还显示托管代码如何在更大的结构内运行。
公共语言运行时(CLR)的功能
公共语言运行时管理内存、线程执行、代码执行、代码安全验证、编译以及其他系统服务。这些功能是在公共语言运行时上运行的托管代码所固有的。
· 至于安全性,取决于包括托管组件的来源(如 Internet、企业网络或本地计算机)在内的一些因素,托管组件被赋予不同程度的信任。
· 运行时强制实施代码访问安全。例如,用户可以相信嵌入在网页中的可执行文件能够在屏幕上播放动画或唱歌,但不能访问他们的个人数据、文件系统或网络。这样,运行时的安全性功能就使通过 Internet 部署的合法软件能够具有特别丰富的功能。
· 运行时还通过实现称为常规类型系统 (CTS) 的严格类型验证和代码验证基础结构来加强代码可靠性。CTS 确保所有托管代码都是可以自我描述的。各种 Microsoft 编译器和第三方语言编译器都可生成符合 CTS 的托管代码。这意味着托管代码可在严格实施类型保证和类型安全的同时使用其他托管类型和实例。
· 此外,运行时的托管环境还消除了许多常见的软件问题。例如,运行时自动处理对象布局并管理对对象的引用,在不再使用它们时将它们释放。这种自动内存管理解决了两个最常见的应用程序错误:内存泄漏和无效内存引用。
· 运行时还提高了开发人员的工作效率。例如,程序员可以用他们选择的开发语言编写应用程序,却仍能充分利用其他开发人员用其他语言编写的运行时、类库和组件。任何选择以运行时为目标的编译器供应商都可以这样做。以 .NET Framework 为目标的语言编译器使得用该语言编写的现有代码可以使用 .NET Framework 的功能,这大大减轻了现有应用程序的迁移过程的工作负担。
· 尽管运行时是为未来的软件设计的,但是它也支持现在和以前的软件。托管和非托管代码之间的互操作性使开发人员能够继续使用所需的 COM 组件和 DLL。
· 运行时旨在增强性能。尽管公共语言运行时提供许多标准运行时服务,但是它从不解释托管代码。一种称为实时 (JIT) 编译的功能使所有托管代码能够以它在其上执行的系统的本机语言运行。同时,内存管理器排除了出现零碎内存的可能性,并增大了内存引用区域以进一步提高性能。
· 最后,运行时可由高性能的服务器端应用程序(如 Microsoft SQL Server 和 Internet 信息服务 (IIS))承载。此基础结构使您在享受支持运行时承载的行业最佳企业服务器的优越性能的同时,能够使用托管代码编写业务逻辑。
公共语言运行时(CLR)细节
· 若要使公共语言运行时能够向托管代码提供服务,语言编译器必须生成一些元数据来描述代码中的类型、成员和引用。元数据与代码一起存储;每个可加载的公共语言运行时可迁移执行 (PE) 文件都包含元数据。公共语言运行时使用元数据来完成以下任务:查找和加载类,在内存中安排实例,解析方法调用,生成本机代码,强制安全性,以及设置运行时上下文边界。
· 公共语言运行时自动处理对象布局并管理对象引用,当不再使用对象时释放它们。按这种方式实现生存期管理的对象称为托管数据。垃圾回收消除了内存泄漏以及其他一些常见的编程错误。如果您编写的代码是托管代码,则可以在 .NET Framework 应用程序中使用托管数据、非托管数据或者同时使用这两种数据。由于语言编译器会提供自己的类型(如基元类型),因此您可能并不总是知道(或需要知道)这些数据是否是托管的。
· 有了公共语言运行时,就可以很容易地设计出对象能够跨语言交互的组件和应用程序。也就是说,用不同语言编写的对象可以互相通信,并且它们的行为可以紧密集成。例如,可以定义一个类,然后使用不同的语言从原始类派生出另一个类或调用原始类的方法。还可以将一个类的实例传递到用不同的语言编写的另一个类的方法。这种跨语言集成之所以成为可能,是因为基于公共语言运行时的语言编译器和工具使用由公共语言运行时定义的常规类型系统(CTS),而且它们遵循公共语言运行时关于定义新类型以及创建、使用、保持和绑定到类型的规则。
· 所有托管组件都带有生成它们所基于的组件和资源的信息,这些信息构成了元数据的一部分。公共语言运行时使用这些信息确保组件或应用程序具有它需要的所有内容的指定版本,这样就使代码不太可能由于某些未满足的依赖项而发生中断。注册信息和状态数据不再保存在注册表中(因为在注册表中建立和维护这些信息很困难)。取而代之的是,有关您定义的类型(及其依赖项)的信息作为元数据与代码存储在一起,这样大大降低了组件复制和移除任务的复杂性。
· 语言编译器和工具公开公共语言运行时的功能的方式对于开发人员来说不仅很有用,而且很直观。这意味着,公共语言运行时的某些功能可能在一个环境中比在另一个环境中更突出。您对公共语言运行时的体验取决于所使用的语言编译器或工具。例如,如果您是一位 Visual Basic 开发人员,您可能会注意到:有了公共语言运行时,Visual Basic 语言的面向对象的功能比以前多了。
.NET Framework 类库
· .NET Framework 类库是一个与公共语言运行时紧密集成的可重用的类型集合。该类库是面向对象的,并提供您自己的托管代码可从中导出功能的类型。这不但使 .NET Framework 类型易于使用,而且还减少了学习 .NET Framework 的新功能所需要的时间。此外,第三方组件可与 .NET Framework 中的类无缝集成。