1. 类型转换
2. 隐式转换:任何情况下都可进行
隐式转换规则是:任何类型A,只要其取值范围完全包含在类型B的取值范围内,就可以隐式转换为类型B。
数值类型可以隐式转换的,例如char和ushort完全可以,bool和string一些可以。
3. 显式转换:某些情况下可进行
彼此之间几乎没有什么关系的类型或根本没有关系的类型不能进行强制转换。
语法:
<(var1)var2>
把var2的类型转换为var1
例如:
byte destinationVar;
short sourceVar = 7;
destinationVar = (byte)sourceVar; //把short转换为byte
Console.WriteLine("sourceVar val: {0}", sourceVar);
Console.WriteLine("destinationVar val: {0}", destinationVar);
表达式的溢出检查上下文
checked(<expression>)
unchecked(<expression>)
还可以设置项目的属性
右击solution explorer中的项目,选择properties→ Build→ 右下角的高级
Check for Arithmetic Overflow/Underflow打钩
使用Convert命令进行显式转换
数值的有效表达方式是:首先是一个可选符号(加号或减号),
然后是0位或多位数字,一个句点后跟一位或多位数字,
接着是一个可选的e或E,后跟一个可选符号和一位或多位数字(在这个序列之前或之后)和空格。
按这种方式可以进行许多显式转换:
对于这些转换要注意的一个问题是,它们总是要进行溢出检查,
checked和unchecked关键字以及项目属性设置不起作用。
举例说明
{
short shortResult, shortVal = 4;
int integerVal = 67;
long longResult;
float floatVal = 10.5F;
double doubleResult, doubleVal = 99.999;
string stringResult, stringVal = "17";
bool boolVal = true;
Console.WriteLine("Variable Conversion Examples\n");
doubleResult = floatVal * shortVal; //把short转为float隐式转换,因为float转为short需要显示转换
Console.WriteLine("Implicit, -> double: {0} * {1} -> {2}", floatVal,
shortVal, doubleResult);
shortResult = (short)floatVal; //把float转为short
Console.WriteLine("Explicit, -> short: {0} -> {1}", floatVal,
shortResult);
stringResult = Convert.ToString(boolVal) +
Convert.ToString(doubleVal);
Console.WriteLine("Explicit, -> string: \"{0}\" + \"{1}\" -> {2}",
boolVal, doubleVal, stringResult);
longResult = integerVal + Convert.ToInt64(stringVal);
Console.WriteLine("Mixed, -> long: {0} + {1} -> {2}",
integerVal, stringVal, longResult);
Console.Read();
}
4. 复杂的变量类型
枚举,结构,数组
5. 枚举
enum <typeName> //定义类型,默认int
{
<value1>,
<value2>,
<value3>,
...
<valueN>
}
接着声明这个新类型的变量:
<typeName> <varName>;
并赋值:
<varName> = <typeName>.<value>;
指定其它类型
enum <typeName> : <underlyingType>
{
<value1>, //默认情况,第一个是0
<value2>, //默认情况,第二个是1
<value3>, //默认情况,第三个是2
...
<valueN>
}
枚举的基本类型可以是byte、sbyte、short、ushort、int、uint、long和ulong
指定每个枚举的实际值
enum <typeName> : <underlyingType>
{
<value1> = <actualVal1>,
<value2> = <actualVal2>,
<value3> = <actualVal3>,
...
<valueN> = <actualValN>
}
也可以使用一个值作为另一个枚举的基础值,为多个枚举指定相同的值
enum <typeName> : <underlyingType>
{
<value1> = <actualVal1>,
<value2> = <value1>, //第二个数和第一个数相同
<value3>, //没有赋值的,会自动获取,比上一个值大1
...
<valueN> = <actualValN>
}
namespace Ch05Ex02
{
enum orientation : byte //类型定义代码放在名称空间
{
north = 1,
south = 2,
east = 3,
west = 4
}
class Program
{
static void Main(string[] args)
{
byte directionByte;
string directionString;
orientation myDirection = orientation.north;
Console.WriteLine("myDirection = {0}", myDirection);
directionByte = (byte)myDirection; //强制类型转换
directionString = Convert.ToString(myDirection);
Console.WriteLine("byte equivalent = {0}", directionByte);
Console.WriteLine("string equivalent = {0}", directionString);
Console.ReadKey();
}
}
}
上例中,如果把byte转换为orientation,也是要进行显示转换
myDirection = (orientation)myByte;
并不是所有byte类型变量的值都可以映射为已定义的orientation值
要获得枚举的字符串值,可以使用Convert.ToString()
directionString = Convert.ToString(myDirection);
或者
directionString = myDirection.ToString();
把string 转换为枚举植,要用特定的命令用于此类转换,即Enum.Parse()
(enumerationType)Enum.Parse(typeof(enumerationType), enumerationValueString);
它使用了另一个运算符typeof,可以得到操作数的类型。
对orientation类型使用这个命令,如下所示:
string myString = "north";
orientation myDirection = (orientation)Enum.Parse(typeof(orientation),
myString);
6. 结构
struct <typeName>
{
<memberDeclarations> //包含变量的声明,称为结构的数据成员
}
每个成员的声明都采用如下形式
<accessibility> <type> <name>;
要让调用结构的代码访问该结构的数据成员,可以对<accessibility>使用关键字public
struct route
{
public orientation direction;
public double distance;
}
定义了结构类型后,就可以定义新类型的变量,来使用该结构
route myRoute;
还可以通过句点字符访问这个组合变量中的数据成员
myRoute.direction = orientation.north;
myRoute.distance = 2.5;
namespace Ch5Ex3
{
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;
Console.WriteLine("1) North\n2) South\n3) East\n4) West");
do
{
Console.WriteLine("Select a direction:");
myDirection = Convert.ToInt32(Console.ReadLine());
}
while ((myDirection < 1) || (myDirection > 4));
Console.WriteLine("Input a distance:");
myDistance = Convert.ToDouble(Console.ReadLine());
myRoute.direction = (orientation)myDirection; //引用route成员
myRoute.distance = myDistance; //可改写为myRoute.distance = Convert.ToDouble(Console.ReadLine());
Console.WriteLine("myRoute specifies a direction of {0} and a " +
"distance of {1}", myRoute.direction, myRoute.distance);
Console.ReadKey();
}
}
}
7. 数组
在方括号中指定索引
friendNames[<index>]
然后可写成
int i;
for (i = 0; i < 3; i++)
{
Console.WriteLine("Name with index of {0}: {1}", i, friendNames[i]);
}
8. 声明数组
<baseType>[ ] <name>;
<baseType>可以是任何变量类型,包括本章前面介绍的枚举和结构类型。
数组必须在访问之前初始化,不能像下面这样访问数组或给数组元素赋值:
int [ ] myIntArray;
myIntArray[10] = 5;
数组初始化,方式1
int [ ] myIntArray = { 5, 9, 10, 2, 99 };
数组初始化,方式2
int [ ] myIntArray = new int [5]; //数组有5个元素
使用关键字new显式地初始化数组,用一个常量值定义其大小。
int [ ] myIntArray = new int [arraySize];
使用非常量的变量来进行初始化
数组初始化,方式3,即方法1和2的组合
int[] myIntArray = new int[5] { 5, 9, 10, 2, 99 };
还可以使用变量定义其大小,但是变量必须是一个常量
const int arraySize = 5; //不可以省略const
int[] myIntArray = new int[arraySize] { 5, 9, 10, 2, 99 };
不一定在声明行中初始化数组
int[] myIntArray;
myIntArray = new int[5];
static void Main(string[] args)
{
string[] friendNames = { "Robert Barwell", "Mike Parry",
"Jeremy Beacock" };
int i;
Console.WriteLine("Here are {0} of my friends:",
friendNames.Length); //确定数组中元素的个数
for (i = 0; i < friendNames.Length; i++) //如果把<改成≤,就会出错,因为索引从0开始,而且所有程序都是这样,不会从1开始
{
Console.WriteLine(friendNames[i]);
}
Console.ReadKey();
}
9. foreach循环
foreach (<baseType> <name> in <array>)
{
// can use <name> for each element
}
上面的例子可更改为
static void Main(string[] args)
{
string[] friendNames = { "Robert Barwell", "Mike Parry",
"Jeremy Beacock" };
Console.WriteLine("Here are {0} of my friends:",
friendNames.Length);
foreach (string friendName in friendNames)
{
Console.WriteLine(friendName);
}
Console.ReadKey();
}
foreach循环代替for循环,其主要区别是,foreach对数组内容只读访问,不能改变任何元素值,可是for可以改变。
foreach (string friendName in friendNames)
{
friendName = "Rupert the bear";
}
以上循环就是错误的
10. 多维数组
二维数组声明
<baseType>[,] <name>;
多维数组声明(四维)
<baseType>[,,,] <name>;
声明一个二维数组,而且初始化
double[,] hillHeight = new double[3,4];
声明一个四维数组,而且初始化
double[,] hillHeight = { { 1, 2, 3, 4 }, { 2, 3, 4, 5 }, { 3, 4, 5, 6 } };
通过提供字面值隐式定义了这些维度
要访问多维数组中的每个元素,只需指定它们的索引,并用逗号分隔开
hillHeight[2,1]
这个表达式将访问上面定义的第3个嵌套数组中的第2个元素(其值是4)。
因为,索引从0开始,第一个数字指定花括号对,第2个数字指定该对花括号中的元素。
所以,上面的四维数组用图可表示为
foreach循环可以访问多维数组中的所有元素,其方式与访问一维数组相同
double[,] hillHeight = { { 1, 2, 3, 4 }, { 2, 3, 4, 5 }, { 3, 4, 5, 6 } };
foreach (double height in hillHeight)
{
Console.WriteLine("{0}", height);
}
元素的输出顺序与赋予字面值的顺序相同(这里显示了元素的标识符,而不是实际值)
hillHeight[0,0]
hillHeight[0,1]
hillHeight[0,2]
hillHeight[0,3]
hillHeight[1,0]
hillHeight[1,1]
hillHeight[1,2]
...
11. 数组的数组
声明数组的数组
int [ ] [ ] jaggedIntArray;
下述锯齿数组包含10个数组,每个数组又包含一个整数数组,其元素是1~10的约数
int [ ] [ ] divisors1To10 = { new int[] { 1 },
new int [ ] { 1, 2 },
new int [ ] { 1, 3 },
new int [ ] { 1, 2, 4 },
new int [ ] { 1, 5 },
new int [ ] { 1, 2, 3, 6 },
new int [ ] { 1, 7 },
new int [ ] { 1, 2, 4, 8 }, new int [ ] { 1, 3, 9 }, new int [ ] { 1, 2, 5, 10 } };
foreach (int[] divisorsOfInt in divisors1To10)
{
foreach(int divisor in divisorsOfInt)
{
Console.WriteLine(divisor);
}
}
12. 字符串的处理
string类型变量可以看作是char变量的只读数组。这样,就可以使用下面的语法访问每个字符:
string myString = "A string";
char myChar = myString[1];
但是,不能用这种方式为各个字符赋值
为了获得一个可写的char数组,可以使用下面的代码
string myString = "A string";
char [ ] myChars = myString.ToCharArray();
接着就可以采用标准方式处理char数组了
foreach (char character in myString)
{
Console.WriteLine("{0}", character);
}
还可以使用myString.Length获取元素的个数
string myString = Console.ReadLine();
Console.WriteLine("You typed {0} characters.", myString.Length);
<string>.ToLower()和<string>.ToUpper(),它们可以分别把字符串转换为大写或小写形式
<string>.Trim() 可以删除输入字符串中的空格
也可以使用这些命令删除其他字符,只要在一个char数组中指定这些字符即可
char [ ] trimChars = {' ', 'e', 's'};
string userResponse = Console.ReadLine();
userResponse = userResponse.ToLower();
userResponse = userResponse.Trim(trimChars);
if (userResponse == "y")
{
// Act on response.
}
这将从字符串的前面或后面删除所有空格、字母e和s
<string>.TrimStart()和<string>.TrimEnd()命令,可以把字符串的前面或后面的空格删掉。
<string>.PadLeft()和<string>.PadRight(),可以在字符串的左边或右边添加空格,使字符串达到指定的长度
<string>.PadX(<desiredLength>);
myString = "Aligned";
myString = myString.PadLeft(10);
在myString中把3个空格添加到单词Aligned的左边
myString = "Aligned";
myString = myString.PadLeft(10, '-');
将在myString的开头加上3个短横线
{
string myString = "This is a test.";
char[] separator = { ' ' }; //该数组中只有一个元素,空格字符
string[] myWords;
myWords = myString.Split(separator); //把string转换为string数组
foreach (string word in myWords)
{
Console.WriteLine("{0}", word);
}
Console.ReadKey();
}
13. 在VS输入代码时,有时候自动感知对话框会遮盖代码,可以按ctrl键,使命令列表变为透明。