您的位置:首页 > 编程语言 > C#

C# 值类型、引用类型、装箱和拆箱、变量和常量

2014-03-24 16:41 267 查看
c#的值类型可以分为以下几种:

●简单类型(Simple types)

●结构类型(Struct types)

●枚举类型(Enumeration types)

简单类型

表4-1 整数类型

数据类型   特征            取值范围

sbyte     有符号          8位整数 在-128到127之间

byte      无符号8位整数   在0到255之间

short     有符号16位整数  在-32768到32767之间

ushort    无符号16位整数  在0到65535之间

int       有符号32位整数  在-2147483648到2147483647之间

uint      无符号32位整数  0到4294967295之间

long      有符号64位整数  在-9223372036854775808到9223372036854775807之间

ulong     无符号64位整数  0和18446744073709551615之间

 

布尔类型

在C#中,分别采用true和false两个值来表示。

注意:在C和C++中,用0来表示“假”,其它任何非0的式子都表示“真”。这种不正规的表达在C#中已经被废弃了。在C#中,true值不能被其它任何非零值所代替。在其它整数类型和布尔类型之间不再存在任何转换,将整数类型转换成布尔类型是不合法的:

bool x=1 //错误,不存在这种写法。只能写成x=true或x=false

 

实数类型

●单精度:取值范围在正负 1.5×10-45 到 3.4×1038 之间,精度为 7 位数。

●双精度:取值范围在正负 5.0×10-324 到 1.7×10308 之间,精度为 15 到 16 位数。

 

C#还专门为我们定义了一种十进制类型(decimal),主要用于方便我们在金融和货币方面的计算。

十进制类型是一种高精度、128 位数据类型,它所表示的范围从大约 到 的 28 至 29 位有效数字。注意,该精度是用位数(digits)而不是以小数位(decimal
places)来表示的。运算结果准确到 28 个小数位。十进制类型的取值范围比double类型的范围要小得多,但它更精确。
当定义一个decimal变量并赋值给它时,使用m下标以表明它是一个十进制类型,如:

decimal d_value=10.m;

如果省略了m,在变量被赋值之前,它将被编译器当作双精度(double)类型来处理。

 

字符类型

C#提供的字符类型按照国际上公认的标准,采用Unicode字符集。一个Unicode的标准字符长度为 16 位,用它可以来表示世界上大多数语言。

另外,我们还可以直接通过十进制转义符(前缀\x)或Unicode表示法给字符型变量赋值(前缀\u),如下面对字符型变量的赋值写法都是正确的:

char c='\x0061'; //c 为小写字母 a ,0x61(16进制) == 97(10进制)

char c='\u0061'; //c 为小写字母 a 。也是 16 进制形式。

注意:在C和C++中,字符型变量的值是该变量所代表的ASCⅡ码,字符型变量的值作为整数的一部分,可以对字符型变量使用整数进行赋值和运算。而这在C#中是被禁止的。

 

表4-2 转义符(Escape Sequences)

转义符 字符名

\0     空字符

\a     感叹号(Alert)

\n     新行

\r     回车

结构类型

struct PhoneBook{

  public string name;

  public string uint age;

  public string phone;

  public struct address{

      public string city;

      public string street;

      public uint no;

  }

}

枚举类型

为枚举类型的元素所赋的值的类型限于long、int、short和byte等整数类型。
enum WeekDay

{

      Sunday,  //值为 0, 也可以写成 Sunday = 11, 则后面的依次加 1 ,分别为 12, 13, ...

      Monday,  //值为 1

      Tuesday,  //值为 2

      Wensday  //值为 3

      ...



 

C#中的引用类型有四种:

●类

●代表

●数组

●接口



类是一种包含数据成员、函数成员和嵌套类型的数据结构。

  - 类的数据成员有常量、域和事件。

  - 函数成员包括方法、属性、索引指示器、运算符、构造函数和析构函数。

类和结构同样都包含了自己的成员,但它们之间最主要的区别在于:类是引用类型,而结构是值类型。

 

在C#语言中取消了指针这个概念。当然,对指针恋恋不舍的程序员仍然可以在C#中使用指针,但必须声明这段程序是“非安全(unsafe)”的。而我们在这里要介绍的是C#的一个引用类型--代表(delegate)。

代表(delegate)

代表在C#是类型安全的。

在代表的实例中,我们可以封装一个静态方法,也可以封装一个非静态的方法。我们看下面的例子:

程序清单4-2:

using System;

delegate int MyDelegate();  //声明一个代表

public class MyClass

{

  public int InstanceMethod(){

    console.WriteLine("Call the instance method.");

    return 0;

  }

  static public int StaticMethod(){

    Console.WriteLine("Call the static method.");

    return 0;

    }

  }

  public class Test

  {

    static public void Main()

    {

      MyClass p=new MyClass();

      //将代表指向非静态的方法 InstanceMethod

      MyDelegate d=new MyDelegate(p.InstanceMethod);

      //调用非静态方法

      d();

      //将代表指向静态的方法StaticMethod

      d=new MyDelegate(MyClass.StaticMethod);

      //调用静态方法

      d();

      }

}

程序的输出结果是:

call the instance method.

call the static method.

 

例二:

using System;

using System.Collections.Generic;

using System.Text;

namespace DelegateDemo

{

    class Class1

    {

        delegate double processDelegate(double db1, double db2);

        static double Multiply(double db1, double db2)

        {

            return db1 * db2;

        }

        static double Divide(double db1, double db2)

        {

            return db1 / db2;

        }

        static void NamedMethod(string strInput,double dbNum1,double dbNum2)

        {

            processDelegate process;          

            if (strInput == "M")

                process = new processDelegate(Multiply);

            else

                process = new processDelegate(Divide);
            Console.WriteLine("结果为:{0}", process(dbNum1, dbNum2));

        }

        static void AnonymousMethod(string strInput, double dbNum1, double dbNum2)

        {

            processDelegate process;

            if (strInput == "M")

                process = delegate(double db1, double db2){return db1 * db2;};
            else

                process = delegate(double db1, double db2) { return db1 / db2; };

            Console.WriteLine("结果为:{0}", process(dbNum1, dbNum2));

        }

        /// <summary>

        /// 应用程序的主入口点。

        /// </summary>

        [STAThread]

        static void Main(string[] args)

        {

            //

            // TODO: 在此处添加代码以启动应用程序

            Console.WriteLine("请输入两个小数,用逗号分割");

            string strInput = Console.ReadLine();

            int commmaPos = strInput.IndexOf(',');

            double dbNum1 = Convert.ToDouble(strInput.Substring(0, commmaPos));

            double dbNum2 = Convert.ToDouble(strInput.Substring(commmaPos + 1));

            Console.WriteLine("输入M表示乘法,或者D表示除法");

            strInput = (Console.ReadLine()).ToUpper();

            //使用命名方法

            Console.WriteLine("使用命名方法委托");

            NamedMethod(strInput,dbNum1,dbNum2); 

            //使用匿名方法

            Console.WriteLine("使用匿名方法委托");

            AnonymousMethod(strInput, dbNum1, dbNum2);

            //Console.Read();

        }

    }



数组

在C#中数组可以是一维的也可以是多维的,同样也支持矩阵和参差不齐的数组。

一维数组最为普遍,用的也最多。我们先看一看下面的例子:

程序清单4-3:

using System:

class Test

{

  static void Main(){

    int[] arr=new int[5];

    for(int i=0;i〈arr.Length;i++)

       arr[i]=i*i;

    for(int i=0;i〈arr.Length;i++)

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

  }

}这个程序创建了一个基类型为int型的一维数组,初始化后逐项输出。其中arr.Length表示数组元素的个数。程序的输出为:

arr[0]=0

arr[1]=1

arr[2]=4

arr[3]=9

arr[4]=16

上面的例子中我们用的是一维的,很简单吧!下面我们介绍多维的:

class Text

{

  static void Main(){      //可动态生成数组的长度

     string[] a1;  //一维string数组

     string[,] a2  //二维

     string[,,] a3 //三维

     string[][] j2;  //可变数组(数组)

     string[][][][] j3; //多维可变数组

}在数组声明的时候可以对数组元素进行赋值,或者叫做对数组的初始化。也可以在使用的时候进行动态赋值。看下面的例子:

class Test

{

  static void Main(){

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

    int[,] a2=new int[,] {{1,2,3},{4,5,6}};

    int[,,] a3=new int[10,20,30];

    int[][] j2=new int[3][];

    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};

   }

}

上面的例子我们可以看出数组初始化可以用几种不同的类型,因为它要求在一个初始化时要确定其类型。比如下面的写法是错误的:

class Test

{

  static void F(int[] arr){}

  static void Main(){

    F({1,2,3});  //错误

  }

}

因为数组初始化时{1,2,3}并不是一个有效的表达式。我们必须要明确数组类型:

class Test

{

  static void F(int[] arr) {}

  static void Main(){

     F(new int[] {1,2,3});

  }

}

 

例:

声明:static int Find(int value,int[] array){...}

可以这样调用:Console.WriteLine(Find(3,new int[] {5,4,3,2,1}));

 

C#的装箱(boxing)和拆箱(unboxing) 

装箱和拆箱机制使得在C#类型系统中,任何值类型、引用类型和object(对象)类型之间进行转换,我们称这种转化为绑定连接。

简单地说,有了装箱和拆箱的概念,对任何类型的值来说最终我们都可以看作是object类型。

 

装箱转换是指将一个值类型隐式地转换成一个object类型,或者把这个值类型转换成一个被该值类型应用的接口类型(interface-type)。

隐士装箱

    int i=10;

    object obj=i;

显式装箱

    int i=10;

    object obj=object(i);

 

我们可以假想存在一个boxing类型,其声明如下:

class T_Box

{

    T value;

    T_Box(Tt){

    value=t;

    }//该类型的构造函数

}

这里T表示将要装箱的值的类型,它可以是int、char、enum等等。现在我们要将类型为T的值v装箱,其执行过程为:执行new T_Box(v),将返回结果的实例作为对象类型的值,那么下面的语句:

int i=10;

object obj=i;

等价于:

int i=10;

object obj=new int_Box(i); //装i装箱成对象obj

 

程序清单4-4:

using System

class Test{

  public static void Main(){

    int i=10;

    object obj=i; //对象类型

    if(obj is int){

      Console.Write("The value of i is boxing!");

    }

    i=20;  //改变i的值

    Console.WriteLine("int:i={0}",i);

    Console.WriteLine("object:obj={0}",obj);

    }

}

输出结果为:

The value of i is boxing!

int:i=20;

object:obj=10;

这就证明了,被装箱的类型的值是作为一个拷贝赋给对象的。
 

拆箱的过程分为两步:

    首先,检查这个对象实例,看它是否为给定的值类型的装箱值。

    然后,把这个实例的值拷贝给值类型的变量。

我们举个例子来看看一个对象拆箱的过程。

int i=10;

object obj=i;

int j=(int)obj;

 

必须注意,装箱转换和拆箱转换必须遵循类型兼容原则。

 

C#中的变量和常量

为变量起名时要遵守C#语言的规定:

●变量名必须以字母开头

●变量名只能由字母、数字和下划线组成,而不能包含空格、标点符号、运算符等其它符号。

●变量名不能与C#中的关键字名称相同。这些关键字我们在附录A中给出。

●变量名不能与C#中的库函数名称相同。

但在C#中有一点是例外,那就是允许在变量名前加前缀“@”。在这种情况下,我们就可以使用前缀“@”加上关键字作为变量的名称。这主要是为了与其他语言进行交互时避免冲突。因为前缀“@”实际上并不是名称的一部分,其它的编程语言就会把它作为一个普通的变量名。在其它情况下,我们不推荐使用前缀“@”作为变量名的一部分。

下面给出了一些合法和非法的变量名的例子:

int i; //合法

int No.1; //不合法,含有非法字符

string total; //合法

char use; //不合法,与关键字名称相同

char @use; //合法

float Main; //不合法,与函数名称相同

在C#语言中,我们把变量分为七种类型,它们分别是:

静态变量(static varibles),

非静态变量(instance variables),

数组元素(array elements),

值参数(value parameters),

引用参数(reference parameters),

输出参数(output parameters),

局部变量(local variables)。

看下面的例子:

class A

{

  public static int x;

  int y;

  void F(int[] v,int a,ref int b,out int c){

       int i=1;

       c=a+b++;

  }

}在上面的变量声明中,x是静态变量,y是非静态变量,v[0]是数组元素,a是值参数,b是引用参数,c是输出参数,i是局部变量。

 

常量修饰符constant-modifier可以是:

●new

●public

●protected

●internal

●private

常量的类型type必须是以下之一:

sbyte,byte,short,ushort,int,uint,long,ulong,char,float,double,decimal,bool,string,枚举类型(enum-type),或引用类型(reference).
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  C# 装箱 拆箱
相关文章推荐