游戏蛮牛学习群(纯技术交流,不闲聊):959392658
游戏蛮牛 手机端
开启辅助访问
 找回密码
 注册帐号

扫一扫,访问微社区

首页   >   博客   >   ccc15724689

C# 基础学习3 - C#的数据类型

2018-9-19 13:00
1.4      C#的数据类型

从大的方面来分,C#语言的数据类型可以分为三种:值类型,引用类型,指针类型,指针类型仅用于非安全代码中。本节重点讨论值类型和引用类型。

1.4.1  值类型和引用类型区别

在C#语言中,值类型变量存储的是数据类型所代表的实际数据,值类型变量的值(或实例)存储在栈(Stack)中,赋值语句是传递变量的值。引用类型(例如类就是引用类型)的实例,也叫对象,不存在栈中,而存储在可管理堆(Managed Heap)中,堆实际上是计算机系统中的空闲内存。引用类型变量的值存储在栈(Stack)中,但存储的不是引用类型对象,而是存储引用类型对象的引用,即地址,和指针所代表的地址不同,引用所代表的地址不能被修改,也不能转换为其它类型地址,它是引用型变量,只能引用指定类对象,引用类型变量赋值语句是传递对象的地址。见下例:

using System;

class MyClass//类为引用类型

{   public int a=0;

}

class Test

{   static void Main()

{   f1();

}

static public void f1()

{   int v1=1;//值类型变量v1,其值1存储在栈(Stack)中

int v2=v1;//将v1的值(为1)传递给v2,v2=1,v1值不变。

v2=2;//v2=2,v1值不变。

MyClass r1=new MyClass();//引用变量r1存储MyClass类对象的地址

MyClass r2=r1;//r1和r2都代表是同一个MyClass类对象

r2.a=2;//和语句r1.a=2等价

}

}

存储在栈中的变量,当其生命周期结束,自动被撤销,例如,v1存储在栈中,v1和函数f1同生命周期,退出函数f1,v1不存在了。但在堆中的对象不能自动被撤销。因此C和C++语言,在堆中建立的对象,不使用时必须用语句释放对象占用的存储空间。.NET系统CLR内建垃圾收集器,当对象的引用变量被撤销,表示对象的生命周期结束,垃圾收集器负责收回不被使用的对象占用的存储空间。例如,上例中引用变量r1及r2是MyClass类对象的引用,存储在栈中,退出函数f1,r1和r2都不存在了,在堆中的MyClass类对象也就被垃圾收集器撤销。也就是说,CLR具有自动内存管理功能。[终于明白了2] 

1.4.2  值类型变量分类

C#语言值类型可以分为以下几种:

l  简单类型(Simple types)

简单类型中包括:数值类型和布尔类型(bool)。数值类型又细分为:整数类型、字符类型(char)、浮点数类型和十进制类型(decimal)。

l  结构类型(Struct types)

l  枚举类型(Enumeration types)

C#语言值类型变量无论如何定义,总是值类型变量,不会变为引用类型变量。

1.4.3  结构类型

结构类型和类一样,可以声明构造函数、数据成员、方法、属性等。结构和类的最根本的区别是结构是值类型,类是引用类型。和类不同,结构不能从另外一个结构或者类派生,本身也不能被继承,因此不能定义抽象结构,结构成员也不能被访问权限控制字protected修饰,也不能用virtual和abstract修饰结构方法。在结构中不能定义析构函数。虽然结构不能从类和结构派生,可是结构能够继承接口,结构继承接口的方法和类继承接口的方法基本一致。下面例子定义一个点结构point:

using System;

struct point//结构定义

{   public int x,y;//结构中也可以声明构造函数和方法,变量不能赋初值

}

class Test

{   static void Main()

{   point P1;

P1.x=166;

P1.y=111;

point P2;

P2=P1;//值传递,使P2.x=166,P2.y=111

point P3=new point();//用new生成结构变量P3,P3仍为值类型变量

}//用new生成结构变量P3仅表示调用默认构造函数,使x=y==0。

}

1.4.4  简单类型

简单类型也是结构类型,因此有构造函数、数据成员、方法、属性等,因此下列语句int i=int.MaxValue;string s=i.ToString()是正确的。即使一个常量,C#也会生成结构类型的实例,因此也可以使用结构类型的方法,例如:string s=13.ToString()是正确的。简单类型包括:整数类型、字符类型、布尔类型、浮点数类型、十进制类型。见下表:

保留字

System命名空间中的名字

字节数

取值范围

sbyte

System.Sbyte

1

-128~127

byte

System.Byte

1

0~255

short

System.Int16

2

-32768~32767

ushort

System.UInt16

2

0~65535

int

System.Int32

4

-2147483648~2147483647

uint

System.UInt32

4

0~4292967295

long

System.Int64

8

-9223372036854775808~9223372036854775808

ulong

System.UInt64

8

0~18446744073709551615

char

System.Char

2

0~65535

float

System.Single

4

3.4E-38~3.4E+38

double

System.Double

8

1.7E-308~1.7E+308

bool

System.Boolean

 

(true,false)

decimal

System.Decimal

16

正负 1.0×10-28 到7.9×1028之间

C#简单类型使用方法和C、C++中相应的数据类型基本一致。需要注意的是:

l  和C语言不同,无论在何种系统中,C#每种数据类型所占字节数是一定的。

l  字符类型采用Unicode字符集,一个Unicode标准字符长度为16位。

l  整数类型不能隐式被转换为字符类型(char),例如char c1=10是错误的,必须写成:char c1=(char)10,char c='A',char c='\x0032';char c='\u0032'。

l  布尔类型有两个值:false,true。不能认为整数0是false,其它值是true。bool x=1是错误的,不存在这种写法,只能写成x=true 或x=false。

l  十进制类型(decimal)也是浮点数类型,只是精度比较高,一般用于财政金融计算。

1.4.5  枚举类型

C#枚举类型使用方法和C、C++中的枚举类型基本一致。见下例:

using System;

class Class1

{   enum Days {Sat=1, Sun, Mon, Tue, Wed, Thu, Fri};

    //使用Visual Studio.Net,enum语句添加在[STAThread]前边

    static void Main(string[] args)

    {   Days day=Days.Tue;

        int x=(int)Days.Tue;//x=2

        Console.WriteLine("day={0},x={1}",day,x);//显示结果为:day=Tue,x=4

    }

}

在此枚举类型Days中,每个元素的默认类型为int,其中Sun=0,Mon=1,Tue=2,依此类推。也可以直接给枚举元素赋值。例如:

enum Days{Sat=1,Sun,Mon,Tue,Wed,Thu,Fri,Sat};

[终于明白了3] 在此枚举中,Sun=1,Mon=2,Tue=3,Wed=4,等等。和C、C++中不同,C#枚举元素类型可以是byte、sbyte、short、ushort、int、uint、long和ulong类型,但不能是char类型。见下例:

enum Days:byte{Sun,Mon,Tue,Wed,Thu,Fri,Sat};//元素为字节类型

1.4.6  值类型的初值和默认构造函数

所有变量都要求必须有初值,如没有赋值,采用默认值。对于简单类型,sbyte、byte、short、ushort、int、uint、long和ulong默认值为0,char类型默认值是(char)0,float为0.0f,double为0.0d,decimal为0.0m,bool为false,枚举类型为0,在结构类型和类中,数据成员的数值类型变量设置为默认值,引用类型变量设置为null。

可以显示的赋值,例如int i=0。而对于复杂结构类型,其中的每个数据成员都按此种方法赋值,显得过于麻烦。由于数值类型都是结构类型,可用new语句调用其构造函数初始化数值类型变量,例如:int j=new int()。请注意,用new语句并不是把int变量变为引用变量,j仍是值类型变量,这里new仅仅是调用其构造函数。所有的数值类型都有默认的无参数的构造函数,其功能就是为该数值类型赋初值为默认值。对于自定义结构类型,由于已有默认的无参数的构造函数,不能再定义无参数的构造函数,但可以定义有参数的构造函数。

1.4.7  引用类型分类

C#语言中引用类型可以分为以下几种:

l  类:C#语言中预定义了一些类:对象类(object类)、数组类、字符串类等。当然,程序员可以定义其它类。

l  接口。

l  代表。

C#语言引用类型变量无论如何定义,总是引用类型变量,不会变为值类型变量。C#语言引用类型对象一般用运算符new建立,用引用类型变量引用该对象。本节仅介绍对象类型(object类型)、字符串类型、数组。其它类型在其它节中介绍。

1.4.8  对象类(object类)

C#中的所有类型(包括数值类型)都直接或间接地以object类为基类。对象类(object类)是所有其它类的基类。任何一个类定义,如果不指定基类,默认object为基类。继承和基类的概念见以后章节。C#语言规定,基类的引用变量可以引用派生类的对象(注意,派生类的引用变量不可以引用基类的对象),因此,对一个object的变量可以赋予任何类型的值:

int x =25;

object obj1;

obj1=x;

object obj2= 'A';

object关键字是在命名空间System中定义的,是类System.Object的别名。

1.4.9  数组类

在进行批量处理数据的时候,要用到数组。数组是一组类型相同的有序数据。数组按照数组名、数据元素的类型和维数来进行描述。C#语言中数组是类System.Array类对象,比如声明一个整型数数组:int[] arr=new int[5];实际上生成了一个数组类对象,arr是这个对象的引用(地址)。

在C#中数组可以是一维的也可以是多维的,同样也支持数组的数组,即数组的元素还是数组。一维数组最为普遍,用的也最多。我们先看一个一维数组的例子:

using System;

class Test

{ static void Main()

{ int[] arr=new int[3];//用new运算符建立一个3个元素的一维数组

for(int i=0;i<arr.Length;i++)//arr.Length是数组类变量,表示数组元素个数

arr[i]=i*i;//数组元素赋初值,arr[i]表示第i个元素的值

for (int i=0;i<arr.Length;i++)//数组第一个元素的下标为0

Console.WriteLine("arr[{0}]={1}",i,arr[i]);

}

}

这个程序创建了一个int类型3个元素的一维数组,初始化后逐项输出。其中arr.Length表示数组元素的个数。注意数组定义不能写为C语言格式:int arr[]。程序的输出为:

arr[0] = 0

arr[1] = 1

arr[2] = 4

上面的例子中使用的是一维数组,下面介绍多维数组:

string[] a1;//一维string数组类引用变量a1

string[,] a2;//二维string数组类引用变量a2

a2=new string[2,3];

a2[1,2]="abc";

string[,,] a3;//三维string数组类引用变量a3

string[][] j2;//数组的数组,即数组的元素还是数组

string[][][][] j3;

在数组声明的时候,可以对数组元素进行赋值。看下面的例子:

int[] a1=new int[]{1,2,3};//一维数组,有3个元素。

int[] a2=new int[3]{1,2,3};//此格式也正确

int[] a3={1,2,3};//相当于int[] a3=new int[]{1,2,3};

int[,] a4=new int[,]{{1,2,3},{4,5,6}};//二维数组,a4[1,1]=5

int[][] j2=new int[3][];//定义数组j2,有三个元素,每个元素都是一个数组

j2[0]=new int[]{1,2,3};//定义第一个元素,是一个数组

j2[1]=new int[]{1, 2, 3, 4, 5, 6};//每个元素的数组可以不等长

j2[2]=new int[]{1, 2, 3, 4, 5, 6, 7, 8, 9};

1.4.10 字符串类(string类)

C#还定义了一个基本的类string,专门用于对字符串的操作。这个类也是在名字空间System中定义的,是类System.String的别名。字符串应用非常广泛,在string类的定义中封装了许多方法,下面的一些语句展示了string类的一些典型用法:

l  字符串定义

string s;//定义一个字符串引用类型变量s

s="Zhang";//字符串引用类型变量s指向字符串"Zhang"

string  FirstName="Ming";

string  LastName="Zhang";

string  Name=FirstName+"  "+LastName;//运算符+已被重载

string  SameName=Name;

char[] s2={'计','算','机','科','学'};

string s3=new String(s2);

l  字符串搜索

string s="ABC科学";

int i=s.IndexOf("科");

搜索"科"在字符串中的位置,因第一个字符索引为0,所以"A"索引为0,"科"索引为3,因此这里i=3,如没有此字符串i=-1。注意C#中,ASCII和汉字都用2字节表示。

l  字符串比较函数

string s1="abc";

string s2="abc";

int n=string.Compare(s1,s2);//n=0

n=0表示两个字符串相同,n小于零,s1<s2,n大于零,s1>s2。此方法区分大小写。也可用如下办法比较字符串:

string s1="abc";

string s="abc";

string s2="不相同";

if(s==s1)//还可用!=。虽然String是引用类型,但这里比较两个字符串的值

s2="相同";

l  判断是否为空字符串

string s="";

string s1="不空";

if(s.Length==0)

s1="空";

l  得到子字符串或字符

string s="取子字符串";

string sb=s.Substring(2,2);//从索引为2开始取2个字符,Sb="字符",s内容不变

char sb1=s[0];//sb1='取'

Console.WriteLine(sb1);//显示:取

l  字符串删除函数

string s="取子字符串";

string sb=s.Remove(0,2);//从索引为0开始删除2个字符,Sb="字符串",s内容不变

l  插入字符串

string s="计算机科学";

string s1=s.Insert(3,"软件");//s1="计算机软件科学",s内容不变

l  字符串替换函数

string s="计算机科学";

string s1=s.Replace("计算机","软件");//s1="软件科学",s内容不变

l  把String转换为字符数组

string S="计算机科学";

char[] s2=S.ToCharArray(0,S.Length);//属性Length为字符类对象的长度

l  其它数据类型转换为字符串

int i=9;

string s8=i.ToString();//s8="9"

float n=1.9f;

string s9=n.ToString();//s8="1.9"

其它数据类型都可用此方法转换为字符类对象

l  大小写转换

string s="AaBbCc";

string s1=s.ToLower();//把字符转换为小写,s内容不变

string s2=s.ToUpper();//把字符转换为大写,s内容不变

l  删除所有的空格

string s="A   bc ";

s.Trim();//删除所有的空格

string类其它方法的使用请用帮助系统查看,方法是打开Visual Studio.Net的代码编辑器,键入string,将光标移到键入的字符串string上,然后按F1键。

1.4.11 类型转换

在编写C#语言程序中,经常会碰到类型转换问题。例如整型数和浮点数相加,C#会进行隐式转换。详细记住那些类型数据可以转换为其它类型数据,是不可能的,也是不必要的。程序员应记住类型转换的一些基本原则,编译器在转换发生问题时,会给出提示。C#语言中类型转换分为:隐式转换、显示转换、加框(boxing)和消框(unboxing)等三种。

一.隐式转换

隐式转换就是系统默认的、不需要加以声明就可以进行的转换。例如从int类型转换到long类型就是一种隐式转换。在隐式转换过程中,转换一般不会失败,转换过程中也不会导致信息丢失。例如:

int i=10;

long l=i;

二.显示转换

显式类型转换,又叫强制类型转换。与隐式转换正好相反,显式转换需要明确地指定转换类型,显示转换可能导致信息丢失。下面的例子把长整形变量显式转换为整型:

long l=5000;

int i=(int)l;//如果超过int取值范围,将产生异常

三.加框(boxing)和消框(unboxing)

加框(boxing)和消框(unboxing)是C#语言类型系统提出的核心概念,加框是值类型转换为object(对象)类型,消框是object(对象)类型转换为值类型。有了加框和消框的概念,对任何类型的变量来说最终我们都可以看作是object类型。

加框操作

把一个值类型变量加框也就是创建一个object对象,并将这个值类型变量的值复制给这个object对象。例如:

int i=10;

object obj=i;//隐式加框操作,obj为创建的object对象的引用。

我们也可以用显式的方法来进行加框操作,例如:

int i =10;

object obj=object(i);//显式加框操作

值类型的值加框后,值类型变量的值不变,仅将这个值类型变量的值复制给这个object对象。我们看一下下面的程序:

using System

class Test

{   public static void Main()

{   int n=200;

object o=n;

o=201;//不能改变n

Console.WriteLine("{0},{1}",n,o);

}

}

输出结果为:200,201。这就证明了值类型变量n和object类对象o都独立存在着。

2. 消框操作

和加框操作正好相反,消框操作是指将一个对象类型显式地转换成一个值类型。消框的过程分为两步:首先检查这个object对象,看它是否为给定的值类型的加框值,如是,把这个对象的值拷贝给值类型的变量。我们举个例子来看看一个对象消框的过程:

int i=10;

object obj=i;

int j=(int)obj;//消框操作

可以看出消框过程正好是加框过程的逆过程,必须注意加框操作和消框操作必须遵循类型兼容的原则。

  1. 3.  加框和消框的使用

定义如下函数:

void Display(Object o)//注意,o为Object类型

{   int x=(int)o;//消框

System.Console.WriteLine("{0},{1}",x,o);

}

调用此函数:int y=20;Display(y);在此利用了加框概念,虚参被实参替换:Object o=y,也就是说,函数的参数是Object类型,可以将任意类型实参传递给函数。

0 0

作者的其他最新博客

评论 (0 个评论)

facelist doodle 涂鸦板

您需要登录后才可以评论 登录 | 注册帐号
返回顶部