目录
● 即使两个变量存储的信息相同,使用不同的类型解释它们时,方式也是不同的。
● 注意: 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(表达式);
static void Main(string[] args)
{
short sourceVar = 281;
byte destinationVar = checked((byte)sourceVar);
WriteLine($"{destinationVar}");
WriteLine($"{sourceVar}");
}
● 注意: 关键字unchecked 替代 checked ,就会得到以前同样的结果,不会出现错误,与默认的做法相同。
● 注意:两个 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。 不过要注意的是: 这里可能产生预料不到的问题。
enum 枚举类型标识符 : 可选择的基础类型
{
value1 = actualVa11,
value2,
value3= value1 ,
value4,
...
valueN = actualVa1N
}
● value2的值 和 value4 的值相同。 注意: 以循环的方式赋值可能会产生错误。
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); // 也可以使用变量本身的myDirection.ToString() 命令,效果相同;
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),就会产生错误。
结构
namespace Ch05Ex03
{
enum orientation : byte
{
north = 1,
south = 2,
east = 3,
west = 4
}
struct route
{
public orientation direction;
public double distance;
}
class Program
{
static void Main(string[] args)
{
route myRoute;
int myDirection = -1;
double myDistance;
WriteLine("1) North\n2) South\n3) East\n4) West");
do
{
WriteLine("选择一个方向:");
myDirection = ToInt32(ReadLine());
} while ((myDirection < 1) || (myDirection > 4));
WriteLine("输入距离:");
myDistance = ToDouble(ReadLine());
myRoute.direction = (orientation)myDirection;//把一个整数值赋给 枚举类型定义的变量,显式转换
myRoute.distance = myDistance; //把一个浮点值赋给了 double变量
WriteLine($"myRoute specifies a direction of {myRoute.direction}"+
$" and a distance of {myRoute.distance}");
ReadKey();
}
}
}
输出结果为:
1) North
2) South
3) East
4) West
选择一个方向:
3
输入距离:
40.3
myRoute specifies a direction of east and a distance of 40.3
数组
● 声明数组的语法为:
任何数据类型[] 标识符;
数组在必须在访问之前初始化,不能像这样访问数组或者给数组元素赋值:
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[3][];
myInt[0] = new int[2] { 2,1 }; //在数组下标为0的位置, 该位置有又是一个数组,里面有2个数字
myInt[1] = new int[4] { 1 ,2,3,4};
myInt[2] = new int[5] { 1 ,2,3,4,5};
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);
}
}
字符串的处理
● 注意: string 类型的变量可以看成 char 变量的只读数组,可以使用下面的语法访问每个字符:
string myString = "Astring";
char myChar = myString[3];
WriteLine($"{ myChar}"); //输出 r
myString[3] = 'f'; //错误,因为它是只读的
但不能采用这种方式为各个字符赋值。 为获得一个可写的 char 数组, 可以使用下面的代码,其中使用了数组变量的 ToCharArray() 命令:
String.toCharArray 方法,作用:将字符串转换为字符数组,该字符数组中存放了当前字符串中的所有字符。
Split函数是编程语言中使用的函数,是指返回一个下标从零开始的一维数组,它包含指定数目的子字符串。
Split和ToCharArray的区别:
(1)split是根据你需要按照的分隔符来分割的,比如:String a = "avc,d,e,s,f"; String []b = a.split(','); 这个就是根据逗号将数据分开,遍历输出得到的b的对象为"avc","d","e","s","f"。
(2)toCharArray是将String对象的每一个下标位的对象保存在char[]中,比如:String a = "abcd"; char[] b = a.toCharArray(); 这个b保存的信息就是 {'a','b','c','d'};
string myString = "Astring";
char[] myChar = myString.ToCharArray();
foreach (char character in myChar)
{
Write($"{character}"); //输出 "Astring"
}
myChar[3] = 'f'; // 改变char 数组中的内容
WriteLine();
foreach (char character in myChar)
{
Write($"{character}"); //输出 "Astfing",第三个字符改了
}
WriteLine();
foreach (char character in myString)
{
Write($"{character}"); //输出 "Astring",
}
还能使用 myString.Length 获取元素个数,这将给出字符中的字符数:
string myString = "Astring";
WriteLine($"{myString.Length}"); //字符数为 7
● 语法为: string标识符.ToLower() 和 string标识符.ToUpper() . 他们分别把字符串转换为 小写或者大写形式。
string userReponse = ReadLine();
if (userReponse.ToLower() == "yes")
{
//statement
}
注意: 这个命令并未真正改变应用它的字符串。 把这个命令与字符串结合使用, 就会创建一个新的字符串, 以便于与另一字符串进行比较, 或者赋给另一个变量。 该变量可以是当前操作的变量,例如:
string userReponse = ReadLine();
if (userReponse.ToLower() == "yes")
{
//statement
}
userReponse = userReponse.ToLower();
下面这样写,是错误的,是没有用:
userReponse.ToLower();
● 语法:string标识符.Trim() 命令可以删除字符串中的空格:
string userReponse = ReadLine();
userReponse = userReponse.ToLower();
userReponse = userReponse.Trim();
if (userReponse == "yes")
{
WriteLine($"{userReponse}");
}
else
WriteLine("error!");
● 也可以使用这些命令删除其他字符,只要在一个char数组中指定这些字符即可:
char[] trimCharas = { ' ','e', 's' };
string userReponse = ReadLine();
userReponse = userReponse.ToLower();
userReponse = userReponse.Trim(trimCharas);
if (userReponse == "y")
{
WriteLine($"{userReponse}");
}
else
WriteLine("error!");
● 还可以使用 string标识符.TrimStart() 和 string标识符.TrimEnd() 命令, 它们可以把字符串前面或后面的空格删掉, 使用这些命令时也可以指定char 数组。
● string标识符.PadLeft() 和 string标识符.PadRight() 命令, 它们可以在字符串的左边或者右边添加空格,使字符串达到指定的长度,语法如下:
string 标识符.PadX(指定的长度);
string myString = "toString";
myString = myString.PadLeft(10);
WriteLine($"{myString}");
这将在myString 中 把2 个空格添加到它的左边(因为tostring这个单词,只有8个字符,所以达不到10个,所以在左边添加两个空格),这些方法可以用于在列中对齐字符串,特别适于放置包含数字的字符串。
● 还可以添加字符到目标字符串上, 但是需要一个char字符,而不是像修整命令那样指定一个char 数组:
string myString = "toString";
myString = myString.PadLeft(10,'+');
WriteLine($"{myString}");
这将在tostring 的左边添加两个++。
● 使用命令 string. Split() 把 string 字符串转换为string 数组,把它在指定的位置隔开,这些数组采用char数组形式。
string myString = "This is a test";
char[] separator = { ' ' };
string[] myWords = myString.Split(separator);
foreach (string word in myWords)
{
WriteLine($"{word}");
}
注意: 得到的每个单词都没有空格,单词的内部和两端都没有空格。 在使用 split() 时,删除了分隔符。