C#教程05_变量的更多内容

目录

5.1 类型转换

5.1.1 隐式转换

5.1.2 显示转换

5.1.3 通过方法转换

5.2 复杂的变量类型

5.2.1 枚举

5.2.2 结构

5.2.3 数组

5.4 练习

5.5 本章要点


5.1 类型转换

(1)复杂类型

枚举:一种变量类型,用户定义了一组可能的离散值,这些值可以用人们能理解的方式使用。

结构:一种合成的变量类型,由用户定义的一组其他变量类型组成。

数组:—包含一种类型的多个变量,允许以索引方式访问各个数值。

(2)类型转换

隐式转换: 从类型A到类型B的转换可在所有情况下进行,执行转换的规则非常简单,可以让编译器执行转换。

显式转换: 从类型A到类型B的转换只能在某些情况下进行,转换规则比较复杂,应进行某种类型的额外处理。

 

5.1.1 隐式转换

隐式转换不需要做任何工作,也不需要另外编写代码。

隐式数值转换

序号

类型

可以安全地转换为

1

byte

short, ushort, int, uint, long, ulong, float, double, decimal

2

sbyte

short, int, long, float, double, decimal

3

short

int, long, float, double, decimal

4

ushort

int, uint, long, ulong, float, double, decimal

5

int

long, float, double, decimal

6

uint

long, ulong, float, double, decimal

7

long

float, double, decimal

8

ulong

float, double, decimal

9

float

double

10

char

ushort, int, uint, long, ulong, float, double, decimal

如果要把一个值放在变量中,而该值超出了变量的取值范围,就会出问题。例如,short类型的变量可以存储0-32 767的数字,而byte可以存储的最大值是255,所以如果要把short值转换为byte值,就会出问题。如果short包含的值在256和32 767之间,相应数值就不能放在byte中。

如果short类型变量中的值小于255,就应能转换这个值吗?答案是可以。具体地说,虽然可以,但必须使用显式转换。执行显式转换有点类似于“我已经知道你对我这么做提出了警告,但我将对其后果负责”。

 

5.1.2 显示转换

明确要求编译器把数值从一种数据类型转换为另一种数据类型时,就是在执行显式转换。因此,这需要另外编写代码,代码的格式因转换方法而异。

static void Main(string[] args)
{
    byte destinationVar;
    short sourceVar = 7;
    destinationVar = (byte)sourceVar;
    WriteLine($"sourceVar val: {sourceVar}");
    WriteLine($"destinationVar val: {destinationVar}");

    ReadKey();

}

运行结果:

static void Main(string[] args)
{
    byte destinationVar;
    short sourceVar = 7;
    destinationVar = sourceVar;
    WriteLine($"sourceVar val: {sourceVar}");
    WriteLine($"destinationVar val: {destinationVar}");

    ReadKey();

}

运行结果:

sourceVar val: 7
destinationVar val: 7
//强制转换,数据丢失
short sourceVar = 281;
byte destinationVar;
destinationVar = (byte)sourceVar;
WriteLine($"sourceVar val: {sourceVar}");
WriteLine($"destinationVar val: {destinationVar}");

运行结果:

sourceVar val: 281
destinationVar val: 25

原因分析:

看看这两个数字的二进制表示,以及可以存储在byte中的最大值255:
  281 = 100011001
   25 = 000011001
  255 = 011111111

源数据的最左边一位丢失了。这会引发一个问题:如何确定数据是何时丢失的?显然,当需要显式地把一种数据类型转换为另一种数据类型时,最好能够了解是否有数据丢失了。如果不知道这些,就会发生严重问题。

对于为表达式设置所谓的溢出检查上下文,需要用到两个关键字——checked和unchecked。按下述方式使用这两个关键字:

checked(<expression>)
unchecked(<expression>)

 

//强制转换,进行溢出检查
short sourceVar = 281;
byte destinationVar;
destinationVar = checked((byte)sourceVar);
WriteLine($"sourceVar val: {sourceVar}");
WriteLine($"destinationVar val: {destinationVar}");

运行结果:

 

 

5.1.3 通过方法转换

(1)使用ToString()方法。所有类型都继承了Object基类,所以都有ToString()这个方法(转化成字符串的方法)。

int i=200;
string s=i.ToString();
//这样字符串类型变量s的值就是”200” 。

(2)通过int.Parse()方法转换,参数类型只支持string类型。

注意:使用该方法转换时string的值不能为NULL,不然无法通过转换;另外string类型参数也只能是各种整型,不能是浮点型,不然也无法通过转换 (例如int.Parse("2.0")就无法通过转换)。

int i;
i = int.Parse("100");

(3)通过int.TryParse()方法转换,该转换方法与int.Parse()转换方法类似,不同点在于int.Parse()方法无法转换成功的情况该方法能正常执行并返回0。也就是说int.TryParse()方法比int.Parse()方法多了一个异常处理,如果出现异常则返回false,并且将输出参数返回0。

int i;
string s = null;
int.TryParse(s,out i);
bool isSucess=int.TryParse("12", out i);//输出值为12;True
bool isSucess=int.TryParse("ss", out i);//输出值为0;False
bool isSucess=int.TryParse("", out i);//输出值为0;False

(4)通过Convert类进行转换,Convert类中提供了很多转换的方法。使用这些方法的前提是能将需要转换的对象转换成相应的类型,如果不能转换则会报格式不对的错误(即前提为面上要过得去例如string类型的“666”可以转换为整数型666,string类型的“666aaa”却转换不成整数型 )。

  static void Main(string[] args)
{
     float num1=82.26f;
     int integer,num2;
     string str,strdate;
     DateTime mydate=DateTime.New;
     //Convert类的方法进行转换
     integer=Convert.ToInt32(num1);
     str=Convert.ToString(num1);
     strdate=Convert.ToString(mydate);
     num2=Convert.ToInt32(mydate);
     Console.WriteLine("转换为整型数据的值{0}",integer);
     Console.WriteLine("转换为字符串{0},str");
     Console.WriteLine("日期型数据转换为字符串值为{0}",strdate);
     Console.ReadKey();
}

(5实现自己的转换,通过继承接口IConventible或者TypeConventer类,从而实现自己的转换。

注意:以Int类型为例,int.Parse,Convert.ToInt和int.TryParse的比较

【1】.参数和适用对象不同

int.Parse的参数数据类型只能是string类型,适用对象为string类型的数据

convert.toInt参数比较多,具体可以参见最下面的重载列表

int.TryParse的参数只能是只能是string类型,适用对象为string类型的数据

【2】.异常情况不同

异常主要是针对数据为null或者为""的情况

Convert.ToInt32 参数为 null 时,返回 0;Convert.ToInt32 参数为 "" 时,抛出异常; int.Parse 参数为 null 时,抛出异常。; int.Parse 参数为 "" 时,抛出异常。int.TryParse()方法 比int.Parse()方法多了一个异常处理,如果出现异常则返回false,并且将输出参数返回0。

【3】.返回值不同

int.TryParse与int.Parse和Convert.ToInt 在返回值的不同是返回bool类型。获取转换后的值是通过out result这个参数获取的。

序号

方法

描述

1

ToBoolean

如果可能的话,把类型转换为布尔型。

2

ToByte

把类型转换为字节类型。

3

ToChar

如果可能的话,把类型转换为单个 Unicode 字符类型。

4

ToDateTime

把类型(整数或字符串类型)转换为 日期-时间 结构。

5

ToDecimal

把浮点型或整数类型转换为十进制类型。

6

ToDouble

把类型转换为双精度浮点型。

7

ToInt16

把类型转换为 16 位整数类型。

8

ToInt32

把类型转换为 32 位整数类型。

9

ToInt64

把类型转换为 64 位整数类型。

10

ToSbyte

把类型转换为有符号字节类型。

11

ToSingle

把类型转换为小浮点数类型。

12

ToString

把类型转换为字符串类型。

13

ToType

把类型转换为指定类型。

14

ToUInt16

把类型转换为 16 位无符号整数类型。

15

ToUInt32

把类型转换为 32 位无符号整数类型。

16

ToUInt64

把类型转换为 64 位无符号整数类型。

 

例子

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;

WriteLine("Variable Conversion Examples\n");
doubleResult = floatVal * shortVal;
WriteLine($"Implicit, -> double: {floatVal} * {shortVal} -> { doubleResult }");
shortResult = (short)floatVal;
WriteLine($"Explicit, -> short: {floatVal} -> {shortResult}");
stringResult = Convert.ToString(boolVal) +
Convert.ToString(doubleVal);
WriteLine($"Explicit, -> string: \"{boolVal}\" + \"{doubleVal}\" -> " +$"{stringResult}");
longResult = integerVal + Convert.ToInt64(stringVal);
WriteLine($"Mixed, -> long: {integerVal} + {stringVal} -> {longResult}");
ReadKey();

运行结果

Variable Conversion Examples

Implicit, -> double: 10.5 * 4 -> 42
Explicit, -> short: 10.5 -> 10
Explicit, -> string: "True" + "99.999" -> True99.999
Mixed, -> long: 67 + 17 -> 84

 

5.2 复杂的变量类型

5.2.1 枚举

枚举的基本类型可以是byte、sbyte、short、ushort、int、uint、long和ulong。

定义枚举

enum<typeName>
  {
    <value1>,
    <value2>,
    <value3>,
    ...
    <valueN>
  }

申明变量并赋值

<typeName><varName>;
<varName> =<typeName>.<value>;

例子:

enum orientation : byte
{
    north = 1,
    south = 2,
    east = 3,
    west = 4,
}
static void Main(string[] args)
{
    //orientation myDirection = orientation.north;
    //WriteLine($"myDirection = {myDirection}");
    //ReadKey();

    byte directionByte;
    string directionString;
    orientation myDirection = orientation.north;
    WriteLine($"myDirection = {myDirection}");
    directionByte = (byte)myDirection;
    directionString = Convert.ToString(myDirection);
    WriteLine($"byte equivalent = {directionByte}");
    WriteLine($"string equivalent = {directionString}");
}

运行结果:

myDirection = north
byte equivalent = 1
string equivalent = north

 

5.2.2 结构

结构就是由几个数据组成的数据结构,这些数据可能具有不同的类型。

根据这个结构,可以定义自己的变量类型。

定义结构

struct<typeName>
  {
   <memberDeclarations>
  }

<memberDeclarations >部分包含变量的声明(称为结构的数据成员),其格式与前面的变量声明一样。每个成员的声明都采用如下形式:

<accessibility><type><name>;

例子:

    enum orientation : byte
        {
            north = 1,
            south = 2,
            east = 3,
            west = 4
        }
        struct route
        {
            public orientation direction;
            public double distance;
        }
static void Main(string[] args)
        {
            route myRoute;
            int myDirection = -1;
            double myDistance;
            WriteLine("1) North\n2) South\n3) East\n4) West");
            do
            {
                WriteLine("Select a direction:");
                myDirection = Convert.ToInt32(ReadLine());
            }
            while ((myDirection < 1) || (myDirection > 4));
            WriteLine("Input a distance:");
            myDistance = Convert.ToDouble(ReadLine());
            myRoute.direction = (orientation)myDirection;
            myRoute.distance = myDistance;
            WriteLine($"myRoute specifies adirection of {myRoute.direction}" +$"and a distance of {myRoute.distance}.");
            ReadKey();
        }

运行结果:

1) North
2) South
3) East
4) West
Select a direction:
5
Select a direction:
7
Select a direction:
2
Input a distance:
168
myRoute specifies adirection of southand a distance of 168.

 

5.2.3 数组

数组有一个基本类型,数组中的各个条目都是这种类型。

数组的条目通常称为元素。

 

声明数组

<baseType> []<name>;

注意:<baseType >可以是任何变量类型,包括枚举和结构类型。数组必须在访问之前初始化。

数组的初始化有两种方式。

可以字面值形式指定数组的完整内容,也可以指定数组的大小,再使用关键字new初始化所有数组元素。要使用字面值指定数组,只需提供一个用逗号分隔的元素值列表,该列表放在花括号中。

int[] myIntArray = { 5, 9, 10, 2, 99 };

使用关键字new显式地初始化数组,用一个常量值定义其大小。这种方式会给所有数组元素赋予同一个默认值,对于数值类型来说,其默认值是0。也可以使用非常量的变量来进行初始化。

int[] myIntArray = new int[arraySize];

可以组合使用这两种初始化方式:

int[] myIntArray = new int[5] { 5, 9, 10, 2, 99 };

如果使用变量定义其大小,该变量必须是一个常量。如果省略了关键字const,就会失败。

const int arraySize = 5;
int[] myIntArray = new int[arraySize] { 5, 9, 10, 2, 99 };

例子

//数组定义方法一
int []myArray1 = { 2, 4, 6, 8, 10 };
//数组定义方法二
int[] myArray2 = new int[5] { 1,2,3,4,5};
//数组定义方法三
int[] myArray3 = new int[3];
myArray3[0] = 3;
myArray3[1] = 6;
myArray3[2] = 9;

 

数组元素遍历

数组遍历方法有两种:for循环、foreach循环

for循环:①提取数组长度;②循环遍历数组元素;

foreach循环:循环取出数组元素

 

foreach语法foreach (<baseType><name> in<array>)   {     // can use<name> for each element   }

foreach (<baseType><name> in<array>)
  {
    // can use<name> for each element
  }

解释:

这个循环会迭代每个元素,依次把每个元素放在变量<name >中,且不存在访问非法元素的危险。不需要考虑数组中有多少个元素,并可以确保将在循环中使用每个元素。

例子1:for循环

static void Main(string[] args)
{
    string[] friendNames = { "Andy", "Bob", "Tony" };
    int i;
    WriteLine($"Here are {friendNames.Length} of my friends:");
    //for循环遍历数组元素
    for (i = 0; i < friendNames.Length; i++)
        WriteLine(friendNames[i]);
    ReadKey();
}

例子2:foreach循环

static void Main(string[] args)
{
    string[] friendNames = { "Andy", "Bob", "Tony" };
    int i;
    WriteLine($"Here are {friendNames.Length} of my friends:");
    //for循环遍历数组元素
    foreach (string friendname in friendnames)
        WriteLine(friendname);
    ReadKey();
}

运行结果:

Here are 3 of my friends:
Andy
Bob
Tony

 

多维数组

<baseType>[,]<name>;
<baseType>[,,,]<name>;

例子:

double[,] hillHeight = new double[3,4];

例子

static void Main()
{
    int[,] hillHeight =new int[3,4] { {1,2,3,4},{5,6,7,8},{9,10,11,12} };
    WriteLine(hillHeight[1,2]);
    WriteLine(hillHeight.Length);
    foreach (int k in myArray)
        Write(k+"\t");
}

运行结果:

7
12
1       2       3       4       5       6       7       8       9       10      11      12

 

数组的数组(锯齿数组)

以使用锯齿数组(jagged array),其中每行的元素个数可能不同。为此,需要有这样一个数组,其中的每个元素都是另一个数组。也可以有数组的数组的数组,甚至更复杂的数组。但是,注意这些数组都必须有相同的基本类型。

//锯齿数组定义1
int[][] jaggedIntArray1;
jaggedIntArray1 = new int[3][] { new int[] { 1, 2, 3 }, new int[] { 1 },  new int[] { 1, 2 } };
//锯齿数组定义2
int[][] jaggedIntArray2 = { new int[] { 1, 2, 3 }, new int[] { 1 }, new int[] { 1, 2 } };

锯齿数组遍历

foreach (int[] divisorsOfInt in jaggedIntArray1)
    foreach (int divisor in divisorsOfInt)
        WriteLine(divisor);

 

5.3 字符串的处理

string类型的变量可以看成char变量的只读数组。这样,就可以使用下面的语法访问每个字符。

  string myString = "A string";
  char myChar = myString[1];

<string>.ToCharArray() 将字符串转换为数组

<string>.Length 获取元素个数

<string >.ToLower() 将字符串转换为小写

<string >.ToUpper() 将字符串转换为大写

 

例子

string myString = "A string";
char[] myChars = myString.ToCharArray();
//字符串长度
WriteLine($"myString.Length = {myString.Length}.");
//字符串转换为小写
WriteLine($"myString.ToLower() = {myString.ToLower()}");
//字符串转换为大写
WriteLine($"myString.ToUpper() = {myString.ToUpper()}");
WriteLine("myString:");
foreach (char menber1 in myString)
    Write($"{menber1}\t");
WriteLine("\nmyChars:");
foreach (char menber2 in myChars)
    Write($"{menber2}\t");
ReadKey();

运行结果

myString.Length = 8.
myString.ToLower() = a string
myString.ToUpper() = A STRING
myString:
A               s       t       r       i       n       g
myChars:
A               s       t       r       i       n       g

语法:

<string >.Trim() 删除输入字符串前后的空格

<string >.TrimStart() 把字符串前面的空格删掉

<string >.TrimEnd() 把字符串后面的空格删掉

<string >.PadLeft() 在字符串的左边添加空格,使字符串达到指定的长度

<string >.PadRight() 在字符串的右边添加空格,使字符串达到指定的长度

例子

string String= "     Hello World !     ";
WriteLine($"String.Trim() = {String.Trim()}");
WriteLine($"String.TrimStart() = {String.TrimStart()}");
WriteLine($"String.TrimEnd() = {String.TrimEnd()}");
WriteLine($"String.PadLeft(50) = {String.PadLeft(50)}");
WriteLine($"String.PadRight(10) = {String.PadRight(10)}");

运行结果

String.Trim() = Hello World !
String.TrimStart() = Hello World !
String.TrimEnd() =      Hello World !
String.PadLeft(50) =                                 Hello World !
String.PadRight(10) =      Hello World !

语法:

<string >.Split(char) 按照char将字符串切割成小的字符串

例子:

//按照空格切割字符串,形成数组。
string myString ="My name is Tony.";
char separator=' ';
string[] mywords = myString.Split(separator);
foreach (string word in mywords)
    WriteLine($"{word}");

运行结果:

My
name
is
Tony.

 

5.4 练习

(1)下面的转换哪些不是隐式转换?

a. int转换为short

b. short转换为int

c. bool转换为string

d. byte转换为float

答案:

a 不是,int-32 位有符号整数类型;short-16 位有符号整数类型

b 是

c 不是,bool-布尔值;string-引用类型;

d 是,byte-8位无符号整数;float-32为当进度浮点型

 

(2)以short类型作为基本类型编写一个color枚举,使其包含彩虹的颜色加上黑色和白色。这个枚举可使用byte类型作为基本类型吗?

答案:

enum color : short
{
    Red, Orange, Yellow, Green, Blue, Indigo, Violet, Black, White
}

可以,byte类型可以包含0~255之间的数字。

如果枚举项使用不同值,基于byte的枚举可以包含256项;如果给枚举项使用重复的值,就可以包含更多的项。

 

(3)下面的代码可以成功编译吗?为什么?

string[] blab = new string[5] blab[5] = 5th string.

答案:

无法编译代码,

原因如下:

遗漏了语句末尾的分号。

第二行尝试访问blab中不存在的第6个元素。

第二行尝试指定未包含在双引号中的字符串。

修改

string[] blab = new string[5];
blab[4] = "5th string";

 

(4)编写一个控制台应用程序,它接收用户输入的一个字符串,将其中的字符以与输入相反的顺序输出。

答案:

//接收输入的字符,以相反的书序输出
WriteLine("Please input a string:");
string originalString =ReadLine();
int Num = originalString.Length;

string inverseString="";
for (int i = Num - 1; i >= 0; i--)
{
    Write($"{originalString[i]}");
    inverseString += originalString[i];
}
WriteLine($"\ninverseString = {inverseString}");

ReadKey();

运行结果:

Please input a string:
My name is tony .
. ynot si eman yM
inverseString = . ynot si eman yM

 

(5)编写一个控制台应用程序,它接收一个字符串,用yes替换字符串中所有的no。

答案:

WriteLine("Enter a string: ");
string myString = ReadLine();
myString = myString.Replace("no ", "yes ");
WriteLine($"Replaced \"no\" with \"yes\":\n {myString} ");

运行结果:

Enter a string:
no that is not a girl .
Replaced "no" with "yes":
 yes that is not a girl .

 

(6)编写一个控制台应用程序,给字符串中的每个单词加上双引号。

答案:

WriteLine("Please input a sentence:");
string myString = ReadLine();
char blankSpace = ' ';
string[] myWords = myString.Split(blankSpace);
foreach (string word in myWords)
    WriteLine($"\"{word}\"");

运行结果:

Please input a sentence:
my name is tony .
"my"
"name"
"is"
"tony"
"."

 

5.5 本章要点

序号

主题

要点

1

类型转换

值可以从一种类型转换为另一种类型,但在转换时应遵循一些规则。隐式转换是自动进行的,但只有当源值类型的所有可能值都可以在目标值类型中使用时,才能进行隐式转换。也可以进行显式转换,但可能得不到期望的值,甚至可能出错

2

枚举

枚举是包含一组离散值的类型,每个离散值都有一个名称。枚举用enum关键字定义,以便在代码中理解它们,因为它们的可读性都很高。枚举有基本的数值类型(默认是int),可使用枚举值的这个属性在枚举值和数值之间转换,或者标识枚举值

3

结构

结构是同时包含几个不同值的类型。结构用struct关键字定义。包含在结构中的每个值都有名称和类型,存储在结构中的每个值的类型不一定相同

4

数组

数组是同类型数值的集合。数组有固定的大小或长度,确定了数组可以包含多少个值。可以定义多维数组或锯齿数组来保存不同数量和形状的数据。还可以使用foreach循环来迭代数组中的值

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值