C#学习笔记(八)-- 数据类型转换、枚举、结构、数组及字符串的处理

一、类型转换

  数据类型的转换可以分为以下两类:

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

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

  1.隐式转换:

  任何类型A只要其取值范围完全包含在类型B取值范围内,就可以隐式转换为类型B:

ushort destinationvar;
char sourcevar = 'a';
destinationvar = sourcevar;

  short类型的变量可以存储0~32767之间的数字,而byte可以存储的最大值是255,如果要将short转到byte,那么就会产生问题,如果short中存放的值在256~32767之间,那就不能将short转到byte;如果short中存放的值在0~255之间,则可以进行转换,但是必须要进行显式转换

  2.显示转换:

  当short中存放的值在0~255之间时,可以通过强制转换,将其转换为byte类型:

byte destinationvar;
short sourcevar = 7;
destinationvar = (byte)sourcevar;

  此时输出的结果:sourcevar = 7;destinationvar = 7;

  当short中的存放的值属于256~32767之间时,如果进行强制转换则会出现数值错误

byte destinationvar;
short sourcevar = 281;
destinationvar = (byte)sourcevar;

  此时输出的结果:sourcevar = 281;destinationvar = 25;

  281 = 100011001

    25 = 000011001

  255 = 0111111111

  由此可见在将大数强转至小数时会出现数据丢失数据的最左侧数位丢失了

  有两种方式可以避免出现这样的问题:

  其一:特别注意显示转换时的数值范围

  其二:为显式转换增加检查关键字checked或unchecked,称为溢出检查

byte destinationvar;
short sourcevar = 281;
destinationvar = checked(byte)sourcevar;
//destinationvar = unchecked(byte)sourcevar;

  checked在运行时程序会崩溃,而unchecked会和之前一样得出错误的答案。

  3.用Convert命令进行显示转换:

  并不是所有字符串都可以通过Convert命令转换为double类型

Convert.ToDouble("Numble");
//报错"Input string was not in a correct format"

  为成功执行此类转换,所提供的字符串必须是数值的有效表达方式,且该数还必须是不会溢出的数,数值的有效表达方式:首先是一个可选符号(可以是加号或减号),然后是0位或多位数字,一个可选的句点,接着是一个可选的e(大小写均可以),后跟一个可选符号一位或者多位数字,除了还可能有空格(在这个序列之前之后),不能有其他字符。例如:-1.2451e-24

  对于Convert而言,必须要进行溢出检查,checked和unchecked关键字以及项目属性设置不起作用。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using static System.Console;
using static System.Convert;

namespace Ch05Ex01
{
    class Program
    {
        static void Main(string[] args)
        {
            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;//在这里short会隐式转换到float,两个float相乘后转为double(隐式转换)
            WriteLine($"Implicit, -> double: {floatVal} * {shortVal} -> { doubleResult }");
            shortResult = (short)floatVal;//float强转为short(显示转换)
            WriteLine($"Explicit, -> short:  {floatVal} -> {shortResult}");
            stringResult = Convert.ToString(boolVal) +
               Convert.ToString(doubleVal);//ToString直接转为字符串类型,字符串类型并不限制字符串长度
            WriteLine($"Explicit, -> string: \"{boolVal}\" + \"{doubleVal}\" -> " +
                      $"{stringResult}");
            longResult = integerVal + ToInt64(stringVal);//类似与ToDouble可以直接转换字符串的数值部分
            WriteLine($"Mixed, -> long:   {integerVal} + {stringVal} -> {longResult}");
            ReadKey();
        }
    }
}

二、复杂的变量类型

1.枚举

  枚举相当于用户定义了一个自己需要的类型,这个类型的取值范围是用户提供的值的有限集合,定义好类型后再去用该类型声明变量

  定义枚举:

  可以用enum关键字定义枚举,如下所示:

enum<typename>
{
   <value1>,
   <value2>,
      ...
   <valueN>
}

  接着声明这个新类型的变量

<typename><varname>;

  并对该变量进行赋值

<varname> = <typename>.<value>;
//也可以直接写做:
<typename><varname> = <typename>.<value>;

  枚举使用一个基本类型来存储,枚举类型可取的每个值都存储为该基本类型的一个值,默认情况下该类型为int,通过在枚举声明中添加类型,就可以指定其他的基本类型

enum<typename>:<underlyingType>
{
   <value1>,
   <value2>,
      ...
   <valueN>
}

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

  默认情况下,每个值都会根据定义的顺序(从0开始),被自动赋予对应的基本类型值。这意味着<value1>的值是0,<value2>的值是1,<value3>的值是2。

  这个赋值过程可以重写,利用赋值运算符"="指定每个枚举的实际值:

enum<typename>:<underlyingName>
{
   <value1> = <acturalval1>,
   <value2> = <acturalval2>,
          ... ... 
   <valueN> = <acturalvalN>
}

  还可以使用一个值错位另一个枚举的基础值,为多个枚举指定相同的值:

enum<typename>:<underlyingName>
{
   <value1> = <acturalvalue1>,
   <value2> = <value1>,
   <value3>,
   ...
   <valueN> = <acturalvalueN>
}

  由于value3没有进行明确的赋值,因此value3的值应该等于上一个明确赋值的值 + 1,即value2 + 1也就是value1 + 1

  枚举类中的与其赋值的关系并不是数值上的关系,而是类似于编号的性质,常见的枚举中并不需要对每个值进行赋值,赋值的意义在于可以通过类型转换提取出更多的信息

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using static System.Console;
using static System.Convert;

namespace Ch05Ex02
{
    enum orientation : byte
    {
        north = 1,
        south = 2,
        east = 3,
        west = 4
    }
    class Program
    {
        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;//将myDirection的值转换为byte类型
            directionString = Convert.ToString(myDirection);
            //使用(string)进行强制类型转换是行不通的,因为需要进行的处理并不是把存储在枚举变量中的数据放在string变量中,而是更复杂一些
            directionString = myDirection.ToString();//这句话与上面的表达式是等价的
            WriteLine($"byte equivalent = {directionByte}");
            WriteLine($"string equivalent = {directionString}");
            ReadKey();
        }
    }
}

  也可以将string转为枚举值,但是其语法稍微复杂一些,有一个特定的命令用于完成此类转换,即

(enumerationType)Enum.Pase(typeof(enumerationType), enumerationValuestring)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using static System.Console;
using static System.Convert;

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

            byte directionByte;
            string directionString;
            //orientation myDirection = orientation.north;
            string myString = "north";
            orientation myDirection = (orientation)Enum.Parse(typeof(orientation), myString);//将字符值转换为枚举值
            WriteLine($"myDirection = {myDirection}");
            directionByte = (byte)myDirection;//将myDirection的值转换为byte类型
            directionString = Convert.ToString(myDirection);
            //使用(string)进行强制类型转换是行不通的,因为需要进行的处理并不是把存储在枚举变量中的数据放在string变量中,而是更复杂一些
            directionString = myDirection.ToString();//这句话与上面的表达式是等价的
            WriteLine($"byte equivalent = {directionByte}");
            WriteLine($"string equivalent = {directionString}");
            ReadKey();
        }
    }
}

2.结构

  结构是由几个数据组成的数据结构,这些数据可能有不同的类型,根据这个结构可以定义自己的变量类型:

  定义结构:

  struct关键字定义结构,如下所示:

struct<typename>
{
  <memberDeclarations>;
  <memberDeclarations>;
}

  <memberDeclarations>部分包含变量(称为结构的数据成员)的声明(注意分号不要漏写),其格式与前面的变量声明一致,每个成员的声明都采用如下的形式:

<accessibility><type><name>

  要让调用结构的代码访问该结构的数据成员,可以对<accessibility>使用关键字public,例如:

struct route
{
   public orientation direction;
   public double distance;
}

  定义结构类型后,就可以定义结构类型的变量

route myRoute;

  还可以通过句点字符访问这个组合变量中的数据成员

myRoute.direction = orientation.north;
myRoute.distance = 2.5;

  结构和枚举一样,其声明均在主体Main函数以外,在名称空间中声明route结构及其使用的orientation枚举

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using static System.Console;
using static System.Convert;

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("Select a direction:");
                myDirection = ToInt32(ReadLine());
            }
            while ((myDirection < 1) || (myDirection > 4));
            WriteLine("Input a distance:");
            myDistance = ToDouble(ReadLine());
            myRoute.direction = (orientation)myDirection;
            myRoute.distance = myDistance;
            WriteLine($"myRoute specifies a direction of {myRoute.direction} " +
                   $"and a distance of {myRoute.distance}");
            ReadKey();
        }
    }

}

3.数组

  采用下述方式声明数组:

<baseType>[]<arrayName>;

  其中<baseType>可以是任何变量类型,包括本章前面介绍的枚举和结构类型数组必须在使用前进行初始化,初始化方式有以下两种:

  1)用字面值指定数组

int [] myIntArray = {5,6,7,8,9};

  2)利用关键字new显式地初始化数组

int [] myIntArray = new int[5];

  这里用关键字new来显式初始化一个数组,用一个常量来定义其大小,这种方式会给所有数组元素赋一个默认值,对于数值类型来说,其默认值是0。

  也可以使用非常量(arraySize不能是一个const修饰的常量)的变量来进行初始化,例如:

int [] myIntArray = new int[arraySize];

  还可以根据需要组合使用这两种初始化方式:

int [] myIntArray = new int[5] {5,6,7,8,9};

  使用这种方式的话,数组的大小必须与元素的个数相匹配,当数组大小与初始化提供的元素个数不同时就会编译失败。

  可以使用变量来定义其大小,但是该变量必须是一个常量

const int arraySize = 5;
int [] myIntArray = new int[arraySize] {5,6,7,8,9};

  如果省略了关键字const,运行这段代码就会失败。

  与其他的变量类型一样,并非必须在声明数组的代码行中初始化该数组:

int [] myIntArray;
myIntArray = new int[5] {5,6,7,8,9};
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using static System.Console;

namespace Ch05Ex04
{
    class Program
    {
        static void Main(string[] args)
        {
            string[] friendNames = { "Todd Anthony", "Kevin Holton",
                            "Shane Laigle" };
            int i;
            WriteLine($"Here are {friendNames.Length} of my friends:");

            //for (i = 0; i <= friendNames.Length; i++)//当符号改成<=时i可以取到3,但是friendNames[3]并不存在所以会出现报错
            for (i = 0; i < friendNames.Length; i++)
            {
                WriteLine(friendNames[i]);
            }
            ReadKey();
        }
    }
}

  使用for循环可能会存在出现访问非法元素的情况,使用foreach循环可以解决这一问题:

static void main(string[] args)
{
   string[] friendNames = {"Todd Anthony","Kevin Holton","Shane Laigle"};
   WriteLine($"Here are {friendsNames.Length} of my friends:");
   foreach(string friendName in FriendNames)
   {
      WriteLine(friendName);
   }
   ReadKey();

}

  foreach循环只读不写,只能逐个读取出数组中的值,但不能像for循环一样给数组进行赋值。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using static System.Console;

namespace Ch05Ex05
{
    class Program
    {
        static void Main(string[] args)
        {            
            string[] friendNames = { "Todd Anthony", "Kevin Holton",
                                     "Shane Laigle", null, "" };
            foreach (var friendName in friendNames)
            {
                switch (friendName)
                {
                    case string t when t.StartsWith("T")://case声明了一个string类型的变量t,里面保存的是foreach中的friendName
                        WriteLine("This friends name starts with a 'T': " +
                            $"{friendName} and is {t.Length - 1} letters long ");
                        break;
                    case string e when e.Length == 0://声明了一个string类型的变量e,如果friend
                        WriteLine("There is a string in the array with no value");
                        break;
                    case null:
                        WriteLine("There was a 'null' value in the array");
                        break;
                    case var x://定义一个变量var x 用于捕获所有类型的变量
                        WriteLine("This is the var pattern of type: " +
                            $"{x.GetType().Name}");
                        break;
                    default:
                        break;
                }
            }

            WriteLine();
            WriteLine("=================================================");
            WriteLine();

            int sum = 0, total = 0, counter = 0, intValue = 0;
            int?[] myIntArray = new int?[7] { 5, intValue, 9, 10, null, 2, 99 };//问号?的存在旨在让编译器知道这个int[]数组可以包含空对象
            foreach (var integer in myIntArray)
            {
                switch (integer)
                {
                    case 0://case 0用于检查在初始化一个整数时,其默认值是否为0(这一步必须进行)
                        WriteLine($"Integer number '{total}' has a default value of 0");
                        total++;//total是用来记录这个数组里一共有多少个元素
                        break;
                    case int value:
                        sum += value;//记录非0非null元素相加之和
                        WriteLine($"Integer number '{total}' has a value of {value}");
                        total++;
                        counter++;//用于记录一共出现了多少个非0非null的元素
                        break;
                    case null:
                        WriteLine($"Integer number '{total}' is null");
                        total++;
                        break;
                    default:
                        break;
                }
            }
            WriteLine($"{total} total integers, {counter} integers with a " +
                      $"value other than 0 or null have a sum value of {sum}");
            ReadLine();
        }
    }
}

4.多维数组  

  定义一个二维数组可以用以下的方式:

<baseType>[,] = <name>;

  定义多维数组只需要增加逗号即可:

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

  声明和初始化二维数组hillHeight

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

  还可以使用字面值进行初始赋值:

double [,] hillHeight = {{1,2,3,4},{2,3,4,5},{3,4,5,6}};

  通过字面值进行初始赋值的数组其维度与之前相同,通过隐式定义了这些维度

  利用foreach循环可以访问多位数组中的所有元素,其访问方式与访问一维数组相同:

double [,] hillHeight = {{1,2,3,4},{2,3,4,5},{3,4,5,6}};
foreach(double height in hillHeight)
{
   writeLine($"{height}");
}

  元素的输出顺序与赋予字面值的顺序相同

5.数组的数组

  当矩阵中的元素,每行中的元素个数不同,构成一个锯齿型的数组。需要有一个这样的数组,其中的每个元素都是另一个数组,也可以有数组的数组的数组,甚至是更复杂的数组。

  声明数组的数组时,其语法要求在数组的声明中指定多个方括号

int [][] jaggedIntArray;

  初始化数组的数组有以下两种方式:

  1)可以初始化包含其他数组的数组(称之为子数组),然后依次初始化子数组:

jaggedIntArray = new int[2][];
jaggedIntArray = new int[3];
jaggedIntArray = new int[4];

  也可以使用上述字面值赋值的一种改进形式

jaggedIntArray = new int [3][] {new int[] {1,2,3}, new int[] {1}, new int[] {1,2}};

  也可以进行简化,把数组的初始化和声明放在同一行上:

int [][] jaggedIntArray = {new int[] {1,2,3}, new int[] {1}, new int[] {1,2}};

  使用foreach对数组的数组进行循环,由于数组的数组其元素是数组,要想得到其中元素,就要用foreach进行循环的嵌套

int [][] divisors1To10 = { new int[] {1},
                           new int[] {1,2},
                           new int[] {1,2,3},
                           new int[] {1,2,3,4},
                           new int[] {1,2,3,4,5},
                           new int[] {1,2,3,4,5,6},
                           new int[] {1,2,3,4,5,6,7},
                           new int[] {1,2,3,4,5,6,7,8},
                           new int[] {1,2,3,4,5,6,7,8,9},
                           new int[] {1,2,3,4,5,6,7,8,9,10}
                         };
foreach(int[] divisorsOfInt in divisors1To10)//先提取数组的数组里面的每一个数组
{
    foreach(int divisor in divisorsOfInt)//再提取数组中的每一个元素
    {
        WriteLine(divisor);
    }
}

6.字符串的处理

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

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

  但是这样做并不能为各个字符赋值,为了获得一个可写的char数组,可以使用数组变量的ToCharArray()命令:

string myString = "A string";
char[] myChars = myString.ToCharArray();

  更多字符串相关操作P74-75

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using static System.Console;

namespace Ch05Ex06
{
    class Program
    {
        static void Main(string[] args)
        {
            string myString = "This is a test.";
            char[] separator = { ' ' };//split命令将字符串在空格处分解开来
            string[] myWords;
            myWords = myString.Split(separator);
            foreach (string word in myWords)
            {
                WriteLine($"{word}");
            }
            ReadKey();
        }
    }
}

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值