一、基本的数值类型(预定义类型)
1.整数类型
类型 | 大小 | 范围 | BCL名称 | 是否有符号 |
---|---|---|---|---|
sbyte | 8bit | −27~27−1 | System.SByte | 是 |
byte | 8bit | 0~28−1 | System.Byte | 否 |
short | 16bit | −215~215−1 | System.Int16 | 是 |
ushort | 16bit | 0~216−1 | System.UInt16 | 否 |
int | 32bit | −231~231−1 | System.Int32 | 是 |
uint | 32bit | 0~232−1 | System.UInt32 | 否 |
long | 64bit | −263~263−1 | System.Int64 | 是 |
ulong | 64bit | 0~264−1 | System.UInt64 | 否 |
2.浮点类型
浮点数的精度是可变的,由有效数字的个数决定。
类型 | 大小 | 范围 | BCL名称 | 有效数字 |
---|---|---|---|---|
float | 32bit | ±1.5×10−45~±3.4×1038 | System.Single | 6~7 |
double | 64bit | ±5.0×10−324~±1.7×10308 | System.Double | 15~16 |
浮点数的范围和精度如下所示
类型 | 符号位 | 指数位 | 尾数位 |
---|---|---|---|
float | 1bit | 8bit | 23bit |
doublt | 1bit | 11bit | 52bit |
浮点数的有效位数由尾数为决定,float的尾数位占23bit,223=8388608,共有7位,所以float的有效位数为7,其中绝对精准的位数为6,所以其有效位数为6~7位;同理,252=4503599627370496,共16位,所以double的有效位数为15~16。
3. decimal类型
类型 | 大小 | 范围 | BCL名称 | 有效数字 |
---|---|---|---|---|
decimal | 128bit | ±1.0×10−28~大约±7.9×1028 | System.Decimal | 28~29 |
- decimal类型和浮点型有很大的差异,decimal类型的基数是十进制的,而浮点类型的基数是二进制,所以可以decimal类型数据表示的十进制都是精确的值。
- decimal类型和浮点类型之间不存在隐式转换。
4. 其余一些相关内容
(1)字面量后缀
- m、f、d 分别为 decimal、float 和 double 的后缀
- 若没有后缀,其解析顺序为:int、uint、long、ulong
- 具有后缀 u,其解析顺序为:uint、ulong
- 具有后缀 l,其解析顺序为:long、ulong
- 后缀为 ul 或 lu 则解析成 ulong
(2)指数计数法
System.Console.WriteLine(6.023E23f);
输出
6.023E+23
(3)十六进制计数法
为了指定一个十六进制值,要为值附加0x前缀
System.Console.WriteLine(0x002A);
输出
42
(4)将数格式化为十六进制
使用 x 或 X 数值格式说明符
System.Console.WriteLine("0x{0:x}", 42);
输出
0x2A
(5)round-trip 格式化
默认情况下,一旦字面量超过 double 类型的有效位数,后面的数则会被抛弃,为了更加准确地判断 double 类型所对应的字符串值可以使用 round-trip 格式化,格式说明符为 R 或者 r
text = string.Format("{0:R}", number);
二、其他类型
1. 布尔类型
布尔类型也称条件类型,允许包含关键字 true 和 false,其 BCL 名称为 System.Boolean,另外 bool 数据类型占一个字节,尽管理论上来说一个 bit 就足以容纳。
2. 字符类型
字符类型 char 用于表示 16bit 字符,其 BCL 名称为 System.Char,为了输入字符类型的字面量,需要将字符放到一对单引号之中。
事实上字符类型是一个整型(它基于一个整数),只不过它储存的是字符而不是数字,但是字符是可以进行参与算术运算的。
int distance = 'f' - 'c';
System.Console.WriteLine(distance);
输出
3
转义序列 | 字符名称 |
---|---|
\’ | 单引号 |
\” | 双引号 |
\0 | NULL |
\a | Alert |
\b | 退格 |
\f | 换页 |
\n | 换行(newline) |
\r | 回车(return) |
\t | 水平制表符 |
\v | 垂直制表符 |
3. 字符串
字符串类型 string,其 BCL 名称是 System.String
(1)字面量
字符串的字面量需要将文本放入双引号中,字符串由字符构成,所以转义序列可以嵌入字符串内。
(2)@ 字符
在一个字符串前面使用 @ 符号指明转义序列不被处理,这样生成的结果是一个逐字字符串字面量,它不仅将反斜杠当做普通字符处理,而且还会逐字解释所有空白
(3)字符串方法
a. 静态方法
静态方法意味着在调用方法的时候需要在方法名前附加该方法的类型
static string.Format()
:此方法具有和Console.WriteLine()
方法相似的行为,区别在于,前者只是返回结果,并不会在控制台输出。
// example
string text = string.Format("hello world");
static string.Concat()
:连接两个字符串
// example
string text, firstName, lastName;
...
// display "<firstName><lastName>", notice that there is no space between names.
text = string.Concat(firstName, lastName);
System.Console.WriteLine(text);
static int string.Compare()
:比较两个字符串,并返回一个整数
// example
string option;
...
int result = string.Compare(option, "h");
// display:
// 0 if equal
// negative if option < h
// positon if option > h
System.Console.WriteLine(result);
b. 实例方法
实例方法不是以类型名作为前缀,而是以变量名作为前缀
(4) 换行符
在Microsoft Windows平台上,换行符是 /r 和 /n 两个字符的组合,而在 UNIX 上使用的是单个的 \n,为了消除两个平台之间的不一致,一个办法是采用 System.Console.WriteLine() 来输出一个空行,另外一个办法是使用 System.Environment.NewLine。
//此二者输出等价
System.Console.WriteLine("hello world");
System.Console.Write("hello world" + System.Environment.NewLine);
(5)字符串是不可变的
字符串的内容是不能被修改的,只能为其重新赋值。
text.ToUpper();
// 此种方式输出的 text 其大小写并未改变
System.Console.Write(text + System.Environment.NewLine);
...
text = text.ToUpper();
//此次输出为 text 的大写变换
System.Console.Write(text + System.Environment.NewLine);
三、null 和 void
1. null
null值表明变量不引用任何有效对象。
- null 可以作为字符串字面量使用
- null 只能赋值给引用类型、指针类型和可空值类型
将 null 值赋给字符串并不等于为它赋一个空字符串”“,null 意味着变量没有任何值,而”“意味着字符串变量有一个值:空字符串
2. void
在C#中,void并不是一个数据类型,它只是用于指出没有数据类型这一事实
3. 隐式类型的局部变量
只要在代码声明的同时初始化一个变量,就可以将其声明为“隐式”的,即无需指明数据类型,关键字为 var
class Uppercase
{
static void Main()
{
System.Console.Write("Enter text: ");
var text = System.Console.ReadLine();
Var uppercase = text.ToUpper();
System.Console.WriteLine(uppercase);
}
}
原理: var 告诉编译器,应该有编译器根据声明内部所赋的值来推断数据类型。
注意:在数据类型已知的情况下不用;右侧数据应该是非常明显的,否则也不用。
C# 3.0 添加 var 的目的是支持匿名类型。
四、类型的分类
1. 值类型
- 值类型的变量应用的位置为内存中实际存储的位置,因此将第一个变量的值赋给第二个变量时,会在新变量的位置创建一个内存副本,大小为变量值的大小。
- 更改第一个变量的值不会影响第二个变量。
- 预定义类型中除了 string 之外均为值类型。
2. 引用类型
- 引用类型不直接储存值,而是对一个内存位置的引用(内存地址),因此在为变量赋值时只会多出一个地址的内存副本,在数据量较大的情况下,显然引用类型比值类型更省空间。
- 由于引用类型只复制数据的地址,所以改变第一个变量的值,第二个变量也会改变。
-
【总结】
- 如果对象在逻辑上是一个不可变的值则定义成值类型,否则定义成引用类型
五、可空修饰符?
有了这个,可以将 null 赋给值类型
static void Main()
{
int? count = null;
...
}
六、数据类型之间的转换
C# 不支持数值类型转换为布尔类型,为了避免引发歧义。
1. 显示转型和隐式转型
有可能造成数量级或者引发一场的任何转换都需要执行显示转型,即告诉编译器:“相信我,我知道我要干什么。”
- 浮点型和 decimal 之间不支持隐式转换。
- 每个数值类型都包含了一个
Parse()
方法,可以讲字符串转化为对应的数值类型。
string text = "9.11E-31";
float kg = float.Parse(text);
- 从 C# 2.0开始,每个预定义类型都包含了
TryParse()
方法,如果转换失败则返回 false 而并不会引发异常
double number;
string input = System.Console.ReadLine();
if(double.TryParse(input, out number))
{
// converted correctly, now use number
}
System.Convert
可以完成预定于类型(包括 string)之间的相互转换
string middleCText = "278.4375";
double middleC = System.Convert.ToDouble(middleCText);
bool boolean = System.Convert.ToBoolean(middleC);
2. checked 和 unchecked 转换
异常监测,使用方式与 C++ 相仿
- C# 编译器提供了一个命令行将默认行为从 unchecked 改为 checked
- unchecked 关键字:及时编译时打开了 checked 选项,在执行期间 unchecked 也会阻止“运行时”引发异常。
七、数组
1. 数组的声明
- 数组的数据项的数量并不是变量声明的一部分
- 二维数组的第一维对应x轴,第二维对应y轴
string[,] languages;
2. 数组的实例化和赋值
(1) 一维数组
- 声明数组时赋值
string[] languages = { "c#", "java", "c++", "visual basic", "lisp" };
- 声明之后在进行赋值,此时需要使用关键字 new
string[] languages;
// 自C# 3.0 起,不必在 new 后面指定数组的数据类型(string),但还是需要方括号
languages = new string[] { "c#", "java", "c++", "visual basic", "lisp" };
- 在运行时定义维数的大小
string[] languages;
...
languages = new string[size];
- C# 还支持将 new 关键字作为声明语句的一部分
string[] languages = new string[] { "c#", "java", "c++", "visual basic", "lisp" };
//无论何时用 new 作为数组赋值的一部分,都可以同时在方括号内指定数组大小
string[] language = new string[5] { "c#", "java", "c++", "visual basic", "lisp" };
- 分配数组但不指定初始值
string[] languages = new string[];
这么做“运行时”会将每个元素初始化为它们的默认值,可以使用 default()运算符来判断一种数据类型的默认值,如 default(int)会返回 0
- [ ] 应用类型:null
- [ ] 数值类型:零
- [ ] bool类型:false
- [ ] char类型:’\0’
(2) 多维数组
多维数组的声明和初始化的方式和一维数组相差无几,唯一的区别是要用 "," 分隔开来,并且定义的是一个规则的图形(如二维数组是一个 m x n 的矩形)。
(3) 交错数组
交错矩阵是由数组构成的数组。
- 交错数组的声明与使用
int[][] cells = { new int[] {1, 2, 1},
new int[] {1, 2},
new int[] {1}
};
// 输出为第二个数组的第一个元素,即 1
System.Console.WriteLine(cells[1][0]);
(4) 长度
Length 返回数组中元素的总数(比如大小为 2×3×3 的数组则会返回 18),但对于交错数组只统计其元素数(由多少个数组构成)。
3. 字符串作为数组使用
访问 string 类型类似于访问一个字符数组,不过由于字符串的不可变性,因此不能对特定字符赋值。