● 即使两个变量存储的信息相同,使用不同的类型解释它们时,方式也是不同的。
● 注意: bool 和 string 没有隐式转换; char 存储的是数值,所以 char 被当作数值类型。
● 这些类型的隐式转换规则是: 任何类型A,只要其取值范围完全包含在类型B的取值范围内,就可以隐式转换为类型B。
● short 类型的变量可以存储 -32768到32767 之间的整数, 而byte 可以存储的最大值是 0到255, 所以如果把 short 转换为 byte 就会出问题。 如果short类型的变量存储的是256到32767之间的数, 相应数值就不能放在byte 中。
如果说short 类型变量中的存储的数值小于255,short 就可以转换byte , 但是需要显式转换。
显式转换
● 语法为:
(要转换成的数据类型)表达式
注意: 这只是在特殊的情况下可行的,彼此之间几乎没有什么关系的类型或根本没有关系的类型不能进行强制换行。
● 关键字 checked 和 unchecked 可以检查一个值放在一个变量中时, 如果该值过大, 就会导致溢出,这就需要检查。
语法为:
checked(表达式);
unchecked(表达式);
● 注意:两个 short 值相乘的结果并不会返回一个 short值, 因为这个操作的结果很可能大于 3267(这是short类型可以存储的最大值), 操作的结果为int 值。
枚举
● 枚举: 允许定义一个 枚举类型名,然后用枚举类型名声明的变量,其变量的值只能取自 括号内的这些标识符。
enum 枚举类型标识符 : 可取的基本类型
{
}
注意:如果没有写可取的基本类型, 默认情况下该类型为int。 枚举的基本类型可以是: byte sbyte short ushort int uint long ulong.
● 还可以使用一个值(枚举常量)作为另一个枚举(枚举常量)的基础值,为多个枚举指定相同的值。(C++中不可以这样):
enum 枚举类型标识符 : 可选择的基础类型
{
value1 = actualVa11,
value2 = value1 ,
value3,
...
valueN = actualVa1N
}
未赋值的任何值都会自动获得一个初始值, 这里使用的值是从比上一个明确声明的值大1 开始的序列。 例如: value3 的值是 value1 +1。 不过要注意的是: 这里可能产生预料不到的问题。
namespace HelloWorld_Console
{
namespace Ch05Ex02
{
enum orientation : byte
{
north = 1,
south = 2,
east = 3,
west = 4
}
}
class Program
{
static void Main(string[] args)
{
byte directionByte;
string directionString;
HelloWorld_Console.Ch05Ex02. orientation myDirection = HelloWorld_Console.Ch05Ex02.orientation.north;
WriteLine($"myDirection = {myDirection}");
// 把 myDirection 的值转换为 byte 类型,必须用显式转换
directionByte = (byte)myDirection;
directionString = Convert.ToString(myDirection);
WriteLine($"byte equivalent = {directionByte}");
WriteLine($"string equivalent = {directionString}");
//将byte 类型转换为 orientation,也同样需要进行显式转换。
byte myByte = 4; //如果这里写7,即超过了枚举列表中的值,就会直接输出7,不会转换
myDirection = (HelloWorld_Console.Ch05Ex02.orientation)myByte;
WriteLine($"string equivalent = {myDirection}");
ReadKey();
}
}
}
● 注意: 把枚举值转换成其他类型,必须使用显式转换。
在本例中虽然 orientation 的基本类型是 byte , 但是必须使用(byte) 强制类型转换, 把 myDirection 的值转换为 byte 类型。
同理, 如果要将byte 类型转换为 orientation,也同样需要进行显式转换。
● 要获得枚举的字符串值,可以使用 Convert.ToString();
注意: 这里使用 (string) 强制类型转换是不行的,因为需要进行的处理并不仅是把存储在枚举变量中的数据放在string 变量中。
还可以使用变量本身的ToString() 命令, 效果一样:
directionString = myDirection.ToString();
● 也可以把 string 转换为,枚举值, 使用 Enum.Parse() , 语法为:
(枚举的类型)Enum.Parse(typeof(枚举的类型),要转换的string变量)
列如:
string myString= " north ";
orientation myDirection = (orientation))Enum.Parse(typepf(orientation),myString);
运算符typeof 可以得到操作数的类型。
注意: 并非所有的字符串值都会转换为一个 orientation 值。 如果传送的值不能转换为枚举值中的一个,就会产生错误。与C# 中的其他值一样,这些值是区分大小写的, 所以如果字符串与一个值相同,但大小写不同(例如,将myString 设置为 North 而不是 north),就会产生错误。
数组
● 声明数组的语法为:
任何数据类型[] 标识符;
数组在必须在访问之前初始化,不能像这样访问数组或者给数组元素赋值:
int[] myIntArray;
myIntArray[10] = 5;
● 数组的初始化有两种方式, 第一种方式是:用字面值形式指定数组的完整内容
int [] array= {0,1,2,3,4,5};
第二种方式是:指定数组的大小,然后使用new 初始化所有元素
int []array=new int[5];
这里使用一个常量值定义数组的大小,这样的方式会给数组的所有元素赋一个默认值,对于数值类型来说,默认值是0.
也可以使用非常量的变量来进行初始化(c++ 中不可以这样):
int[] array=new int[arraySize];
int a = 6;
int[] array = new int[a];
● 还可以组合上面的初始化方式:
int [] array = new int[5] {0,1,2,3,4};
int [] array = new int[10] {0,1,2,3,4}; //错误
注意:使用这样的方式数组的大小与元素个数必须一致,否则错误。
● 如果使用变量定义其大小,该变量必须是一个常量:
const int arraySize = 5;
int[] myIntArray=new int[arraySize] {0,1,2,3,4};
const int arraySize = 4;
int[] myIntArray = new int[arraySize] { 0, 1, 2 }; //错误,数组大小和元素个数不一致
如果省略了关键字const,语法错误。注意: 这样写,数组的大小与元素个数必须一致,否则错误。
foreach 循环
● 语法为:
foreach(要访问的数组的数据类型 标识符 in 要访问的数组的标识符)
{
WriteLine(标识符);
}
每次迭代,“标识符” 部分的变量都会被初始化为 array中、下一个元素的值。
和for循环的区别是: foreach 循环只对数组的内容进行只读访问,所以不能改变任何元素的值;但是如果使用for 循环,就可以给数组的元素赋值。
多维数组
● 多维数组是使用多个索引访问其元素的数组。
● 声明二维数组的语法为:
数据类型 [,] 标识符; //二维数组
数据类型 [,,,] 标识符; //四维数组
● 初始化二维数组使用类似的语法:
doule[,] myDouble = new double[3,4];
doule[,] myDouble = {{1,2,3,4},{2,3,4,5},{3,4,5,6}};
这个通过字面值赋值,隐式定义了数组的维度。
int c = 3, a = 4;
int[,] myInt = new int[c, a]; //正确
● 访问数组中的元素,只需要指定它们的索引,并用逗号分开:
myDouble[2,1]; //访问元素4
● foreach 循环可以访问数组中的所有元素,其方式与访问一维数组相同:
double[,] myDouble = { { 1, 2, 3, 4 }, { 2, 3, 4, 5 }, { 3, 4, 5, 6 } };
foreach(double height in myDouble)
{
WriteLine("{0}", height);
}
数组的数组
● 上面讨论的可称为矩形数组,因为每一行的元素个数都一样。
● 还有锯齿数组,其中每行的元素个数可能不同,其中的每一个元素都是另外一个数组。但是注意:这些数组都必须有相同的基本类型。
● 声明数组的数组时,要在声明中指定多个方括号对:
int[][] myInt;
● 不能这样声明
int[][] myInt =new[3][4];
也不能这样
int[][] myInt = { { 1, 3, 4 }, { 2, 3, 4, 5 }, { 22, 3 } };
● 初始化的方式有:
int[][] myInt = new int[2][];
myInt[0] = new int[2] { 2,1 };
myInt[1] = new int[4] { 1 ,2,3,4};
int[][] myInt = new int[3][] { new int[] { 1, 2, 3 }, new int[] { 1 }, new int[] { 1, 2 } }; //正确
int[][] myInt = { new int[] { 1, 2, 3 }, new int[] { 1 }, new int[] { 1, 2 } }; //正确
● 可以对锯齿数组使用 foreach 循环,要使用嵌套的foreach循环才可以得到实际数据:
int[][] my2Int = { new int[] { 1, 2, 3 }, new int[] { 1 }, new int[] { 1, 2 } }; //正确
foreach (int divisor in my2Int)
{
WriteLine(divisor); //错误
}
这是因为my2Int 包含 int[ ] 元素而不是int元素。 正确的做法是: 循环遍历每个子数组和数组本身:
int[][] my2Int = { new int[] { 1, 2, 3 }, new int[] { 1 }, new int[] { 1, 2 } }; //正确
foreach (int[] divisor in my2Int)
{
foreach(int temp in divisor)
{
WriteLine(temp);
}
}