[CLR via C#]5.1 基元类型

原文:[CLR via C#]5.1 基元类型

  某些数据类在开发中非常常用,以至于许多编译器允许代码已简化的语法来操作它们。例如可以使用以下语法来分配一个整数: 

System.Int32 a = new System.Int32();

  当然,你肯定不愿意使用这种语法,C#允许使用如下所示的语法:   

int a = 0;

  这种语法不仅增强代码的可读性,而且生成的IL代码和是有System.Int32时生成的IL代码是完全一致的。

  编译器直接支持的数据类型称为基元类型(primitive type)。基元类型直接映射到Framework类库(FCL)中存在的类型。比如以下4行代码都是正确的,生成的IL代码也是相同的。

int a = 0;
System.Int32 a =0;
int a = new int();
System.Int32 a = new System.Inte32();

  下表列出了FCL类型在C#中对应的基元类型:

C#基元类型 FCL类型 CLS相容 说明
sbyte System.SByte NO 有符号8位值
byte System.Byte YES 无符号8位值
short System.Int16 YES 有符号16位值
ushort System.UInt16 NO 无符号16位值
int System.Int32 YES 有符号32位值
uint System.UInt32 NO 无符号32位值
long System.Int64 YES 有符号64位值
ulong System.UInt64 NO 无符号64位值
char System.Char YES 16位Unicode字符
float System.Single YES IEEE32位浮点值
double System.Double YES IEEE64位浮点值
bool System.Boolean YES 一个true/false值
decimal System.Decimal YES 一个128位高精度浮点值,常用于不容许舍入误差的金融计算
string System.String YES 一个字符数组
object System.Object YES 所有类型的基类型
dynamic System.Object YES 对于CLR,dynamic和object完全一致。然而,C#编译器允许使用一个简单的语法,让dynamic变量参与动态调度

 

  可以想象C#编译器自动假定在所有的源代码文件中添加了以下using指令:  

using sbyte = System.Sbyte;
using byte = System.Byte;
using int = System.Int32;
using uint = System.UInt32;
......

  C#语言规范上说:"从风格上上,最好使用关键字,而不是使用完整的系统类型名称"。但本书作者并不同意这种说法,以下是他的一些理由:

  1)很多开发人员困惑于应该使用string还是String。由于C#的string(关键字)是直接映射到System.String(一个FCL类型),所以两者是没有区别的。还有开发人员认为,在32位系统中int是32位整数,在64位系统中就变成64位整数了,事实并不是这样。在C#中,int始终映射到System.Inte32,所有不管什么系统,int都是32位整数,如果都使用Int32就不会产生这种误解。 

  2)在C#中,long映射到System.Int64,当在其他编程语言中,long可能映射到的是Int16或Int32。这样在看别的编程语言时容易产生误解。 

  3)FCL的许多方法都将类型名称作为方法名的一部分。

 

 

BinaryReader br =new BinaryReader(...);

        float val = br.ReadSingle();      //正确,当看上去不自然

        Single val = br.ReadSingle();    //正确,看上去一目了然

   

  4)平时只用C#的许多程序员逐渐淡忘了还可以使用其他语言写面向CLR的代码。因此造成了"C#主义"入侵类库代码。

  

  对基元类型执行许多算数运算都可能造成溢出。不同语言处理溢出也是不同的。C和C++不将溢出视为错误,并允许值回滚;应用程序"若无其事"的运行着。相反,Microsoft Visual Basic总是将溢出视为错误,并会抛出异常。

 

  CLR提供了一些特殊的IL指令,允许编译器选择它认为最恰当的行为。CLR有一个add指令,将两值相加但不检查溢出。还有一个add.ovf指令,作用是两值相加,溢出时抛出异常。类似的还有sub/sub.ovf等。

 

  C#允许开发人员自己决定如何处理溢出。溢出检查默认是关闭的。开发人员可以使用C#编译器控制溢出的一个办法是使用/checked+编译器开关。

 

  C#通过提供checked和unchecked操作符来实现局部是否检查发生溢出。

unchecked:
UInt32 invalid = unchecked((UInt32)(-1));    //OK
checked:
Byte b = 100;
b = checked((Byte)(n+200));    //抛出溢出异常

  C#还提供checked和unchecked语句

checked{
    Byte b = 100;
    b = checked((Byte)(n+200));
}

  在Visaul Studio的"高级生成设置"对话框中可以指定编译器是否检查溢出。

  System.Decimal类型是一个非常特殊的类型。虽然C#将Decimal视为一个基元类型,但CLR则不然,也就是说CLR没有相应的IL指令来决定如何处理Decimal值。Decimal值得处理速度是要慢于其他CLR基元类型的值得处理速度。还有对Decimal来说,checked和uncheked操作符、语句和编译器都是无效的,Decimal溢出时是一定会抛出异常的。

时间: 2024-10-31 11:19:26

[CLR via C#]5.1 基元类型的相关文章

[CLR via C#]5.4 对象哈希码和dynamic基元类型

原文:[CLR via C#]5.4 对象哈希码和dynamic基元类型 FCL的设计者认为,如果能将任何对象的任何实例放到一个哈希表集合中,会带来很多好处.为此,System.Object提供了虚方法GetHashCode,它能获取任意对象的Int32哈希值. 如果你重写了Equals方法,那么还应重写GetHashCode方法.因为在System.Collection.Hashtable类型.System.Collections.Generic.Dictionary类型以及其他一些集合实现中

C#中的基元类型

这篇文章我想复习下C#中的基元类型.虽然搞清楚基元类型的知识并不会是你工作的必要条件,但做为一个搞技术的人来说还是非常有必要的.起码可以对付有些显得比较BT的面试题,哈哈! 关于什么是基元类型,我想并不是每一位开发者都清楚的,有部分的朋友只知道怎么在工作中应用它(例如int,string).如果一个编程基础比较扎实的朋友来说当然不在话下,就不说别人,拿我自己来说,编程三年多,我都不太关心什么是基元类型,它有什么用,其实不知道这些对工作也不会产生决定性的影响.如果你不知道基类型的概念,但会用int

CLR笔记:5.基元,引用和值类型

5.1基元类型 编译器(C#)直接支持的任何数据类型都称为基元类型(primitive type),基元类型直接映射到FCL中存 在的类型.可以认为 using string = System.String;自动产生. FCL中的类型在C#中都有相应的基元类型,但是在CLS中不一定有,如Sbyte,UInt16等等. C#允许在"安全"的时候隐式转型--不会发生数据丢失,Int32可以转为Int64,但是反过来要显示 转换,显示转换时C#对结果进行截断处理. unchecked和che

《Python面向对象编程指南》——2.9 new()方法和元类型

2.9 new()方法和元类型 __new__()方法的另一种用途,作为元类型的一部分,主要是为了控制如何创建一个类.这和之前的如何用__new__()控制一个不可变对象是完全不同的. 一个元类型创建一个类.一旦类对象被创建,我们就可以用这个类对象创建不同的实例.所有类的元类型都是type,type()函数被用来创建类对象. 另外,type()函数还可以被用作显示当前对象类型. 下面是一个很简单的例子,直接使用type()作为构造器创建了一个新的但是几乎完全没有任何用处的类: Useless=

msdn-派生类存放在基类类型vector中,怎么用派生类的函数?

问题描述 派生类存放在基类类型vector中,怎么用派生类的函数? 我已经成功将派生类存放在基类类型的vector表中,也能定位位置,就是不知道怎么使用派生类的函数,只能用基类的函数,求解啊! #include#include#include#includeusing namespace std;class people{public: people() { name = new char[20]; code = 0; sex = new char[8]; number = new char[2

CLR 4.0 有哪些新东西? -- 类型等价

我上篇博文说到了CLR 4.0类型嵌入特性, 那么请大家想一想类型嵌入是谁实现的? 选项A   CLR    选项B  编译器  选项C TlbImp  选项D   微软 My last post talked about the "Type embedding" feature of CLR 4.0. Please think about who implemented "Type embedding"? These are options: A.  CLR   

Safelock 20120229发布 基于文件的锁定基元

Safelock 是一个基于文件的锁定基元,用于无关的进程和线程之间的死锁条件互诉.它提供了 POSIX 和 BSD 文件的锁定优势,如:多线程应用的兼容性,支持567.html">尝试超时锁定,检测崩溃的锁持有者,并详细列出锁定状态(PID,锁定时期,自定义数据). Safelock 20120229该版本是首次发布的版本. 使用范例: &http://www.aliyun.com/zixun/aggregation/37954.html">nbsp;#inclu

简单看看这两个类 String和StringBuilder

我记得以前在园子里面讨论这两个类的文章有很多很多,并且还拿出了很多的测试报告,在什么情况下,谁比谁快,在什么情况下,该用谁 不该用谁等等这些,我这里就不比较了,我就简单看看他们里面的内部实现,那就先看看String吧.   一:String类 说到String类,资料上都说是存在于堆上的一个不可CURD的一个不可变的字符集,当然看到这句话之后就想要看看是不是这样的,然后就 好奇的写了以下代码. class Program { static void Main(string[] args) { s

CLR笔记:18.可空值类型

前言:System.Nullable<T>在FCL中的实现: System.Nullable<T> where T:struct,所以Nullable<T>是一个值类型 有两个只读属性HasValue和Value,以及GetValueOrDefault方法 18.1 C#语法:Int32? 等价于 Nullable<Int32>,于是可以有: Int32? a = 5; Int32? b = null; 允许类型转换:Int32 c = (Int32)a;