我爱我的家园!

成功在于你是否努力,希望在于你是否相信自己!

 

C#深入详解[4.1 数据类型]

4.1  数据类型

4.1.1  C#的数据类型

C#是强类型语言,因此每个变量和对象都必须具有声明类型。C#开发语言的数据类型包括值类型和引用类型。

4.1.2  C#值类型

C#开发语言的值类型有15种,包括bool、byte、char、decimal、double、enum、float、int、long、sbyte、short、struct、uint、ulong和ushort。

4.1.2.1  C#值类型介绍——bool类型

1.bool类型的定义

bool关键字是System.Boolean的别名。它用于声明变量来存储布尔值truefalse,可将布尔值赋给bool变量,也可以将计算为bool类型的表达式赋给bool变量。

功能说明:bool类型的定义。

程序清单4-1

using System;

public class MyClass

{

    static void Main()

    {

        bool J = true;

        char D = '0';

        Console.WriteLine(J);

        J = false;

        Console.WriteLine(J);

        bool abc = (D > 64 && D < 123);

        Console.WriteLine(abc);

    }

}

运行结果如图4-1所示。

图4-1  bool类型的定义

2.bool类型的转换

在C++中,bool类型的值可转换为int类型的值,false等效于零值,而true等效于非零值。但是在C#语言中,不存在bool类型与其他类型之间的相互转换。例如,下列if语句在C#中是非法的,而在C++中则是合法的:

int x = 123;

if (x)   // 注意:在C#中此语句是错误的

{

    printf("x is 非零值.");

}

若要测试int类型的变量,必须将该变量与一个值(例如零)进行显式比较,如下所示:

int x = 123;

if (x != 0)   // C#的判断方式

{

    Console.Write("The value of x is nonzero.");

}

功能说明:从键盘输入一个字符,然后程序检查输入的字符是否是一个字母。如果输入的字符是字母,则程序检查是大写还是小写。这些检查是使用IsLetter和IsLower(两者均返回bool类型)来执行的。

程序清单4-2

using System;

public class BoolTest1

{

    static void Main()

    {

        Console.Write("请输入一个字母: ");

        char c = (char)Console.Read();

        if (Char.IsLower(c))

        {

                Console.WriteLine("这个字符是小写字母.");

        }

        else

        {

                Console.WriteLine("这个字符是大写字母.");

        }

    }

}

运行结果如图4-2所示。

图4-2  bool类型的转换

4.1.2.2  值类型介绍——byte类型

1.byte类型的定义

byte关键字代表一种整型,该类型的存储值如表4-1所示。

表4-1  byte类型

   

   

   

   

byte

0 255

无符号的 8 位整数

System.Byte

2.byte类型的标识

如下例所示声明并初始化byte类型的变量:

byte myByte = 15;

3.byte类型的转换

存在从byte到shortushortintuintlongulongfloatdoubledecimal的预定义隐式转换。

注意

不能将更大存储范围的非文本数值类型隐式转换为byte。

如:byte z = x + y;

以上的赋值语句将产生一个编译错误,原因是赋值运算符右侧的算术表达式在默认情况下的计算结果为int类型。

若要解决此问题,请使用强制转换:

byte z = (byte)(x + y);

但是,在目标变量具有相同或更大的存储时,使用下列语句是可能的:

int x = 25, y = 20;

int m = x + y;

long n = x + y;

4.1.2.3  值类型介绍——char类型

1.char类型的定义

char关键字用于声明表4-2所示范围内的Unicode字符。Unicode字符是16位字符,用于表示世界上多数已知的书面语言。

表4-2  char类型

   

   

   

   

char

U+0000 U+ffff

16 Unicode

System.Char

2.char类型的标识

char类型的常数可以写成字符、十六进制换码序列或Unicode表示形式。你也可以显式转换整数字符代码。以下所有语句均声明了一个char变量并用字符Y将其初始化:

char char1 = 'Y';        // 字符

char char2 = '\x0050';   // 16进制

char char3 = (char)89;   // 准会整数字符代码

char char4 = '\u0035';   // Unicode

3.char类型的转换

char可以隐式转换为ushortintuintlongulongfloatdoubledecimal。但是,不存在从其他类型到char类型的隐式转换。

4.1.2.4  值类型介绍——decimal类型

1.decimal类型的定义

decimal关键字表示128位数据类型。同浮点型相比,decimal类型具有更高的精度和更小的范围,这使它适合于财务和货币计算。该类型的存储值如表4-3所示。

表4-3  decimal类型

   

   

   

   

decimal

± 1.0 * 10e−28 至± 7.9 *10e28

28 29 位有效

System.Decimal

2.decimal类型的标识

如果希望实数被视为decimal类型,请使用后缀m或M,例如:

decimal myMoney = 300.3m;

如果没有后缀m,数字将被视为double类型,从而导致编译器错误。

3.decimal类型的转换

整型被隐式转换为decimal,其计算结果为decimal。因此,可以用整数初始化十进制变量而不使用后缀,如下所示:

decimal myMoney = 300;

在浮点型和decimal类型之间不存在隐式转换;因此,必须使用强制转换在这两种类型之间进行转换,如下所示:

decimal myMoney = 99.8m;

double x = (double)myMoney;

myMoney = (decimal)x;

4.decimal类型的十进制输出

可以通过使用String.Format方法或System.Console.Write方法(它调用String.Format())来格式化结果。指定货币格式时需要使用标准货币格式字符串“C”或“c”。

在此例中,同一个表达式中混合使用了decimal和int,计算结果为decimal类型。

如果试图使用下面这样的语句添加double和decimal变量:

double x = 8;

Console.WriteLine(d + x); // Error

将导致下列错误:

Operator '+' cannot be applied to operands of type 'double' and 'decimal'

功能说明:decimal类型的十进制输出。

程序清单4-3

using System;

public class Decimal_Test

{

    static void Main()

    {

        decimal d = 5.6m;

        int y = 9;

        Console.WriteLine(d + y);  

    }

}

输出结果如图4-3所示。

图4-3  decimal类型的十进制输出

功能说明:在此例中,输出用货币格式字符串格式化。注意:其中x被舍入,因为其小数点位置超出了$0.99。而表示最大精确位数的变量y严格按照正确的格式显示。

程序清单4-4

using System;

public class Format_decimal_Test

{

    static void Main()

    {

        decimal x = 0.999m;

        decimal y = 1234567890m;

        Console.WriteLine("My amount = {0:C}", x);

        Console.WriteLine("Your amount = {0:C}", y);

    }

}

输出结果如图4-4所示。

图4-4  输出用货币格式字符串格式化

4.1.2.5  值类型介绍——double类型

1.double类型的定义

double关键字表示存储64位浮点值的简单类型,该类型的存储值如表4-4所示。

表4-4  double类型

   

   

   

   

double

± 5.0 × 10 - 324 到± 1.7 × 10308

15 16

System.Double

2.double类型的标识

默认情况下,赋值运算符右侧的实数被视为double。但是,如果希望整数被视为double,请使用后缀d或D,例如:

   double x = 8D;

3.double类型的转换

可在一个表达式中兼用数值整型和浮点型。在此情况下,整型将转换为浮点型。根据以下规则计算表达式:

— 如果其中一个浮点类型为double,则表达式的计算结果为double类型,在关系表达式或布尔表达式中为bool类型。

— 如果表达式中不存在double类型,则表达式的计算结果为float类型,在关系表达式或布尔表达式中为bool类型。

浮点表达式可以包含下列值集:

— 正零和负零。

— 正无穷和负无穷。

— 非数字值(NaN)。

— 有限的非零值集。

功能说明:在下面的示例中,一个int、一个short、一个float和一个double相加,计算结果为double类型。

程序清单4-5

using System;

class double_Mixed_Test

{

    static void Main()

    {

        int i1 = 52;

        float f1 = 9.5f;

        short s1 = 9;

        double d1 = 4.2E+3;

        Console.WriteLine("数据总和等于: {0}", i1 + f1 + s1 + d1);

    }

}

运行结果如图4-5所示。

图4-5  double类型的转换

4.1.2.6  值类型介绍——enum类型

1.enum类型的定义

enum关键字是一种由一组称为枚举数列表的命名常数组成的独特类型。每种枚举类型都有基础类型,该类型可以是除char以外的任何整型。

注意

枚举元素的默认基础类型为int

2.enum类型的标识

默认情况下,第一个枚举数的值为0,后面每个枚举数的值依次递增1。例如:

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

此枚举中,强制元素序列从1而不是0开始。例如:

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

注意

枚举数的名称中不能包含空白。

3.enum类型的转换

基础类型指定为每个枚举数分配的存储大小。但是,从enum类型到整型的转换需要用显式类型转换来完成。例如,下面的语句通过使用强制转换从enum转换为int,将枚举数Sun赋给int类型的变量:

int x = (int)Days.Sun;

4.enum类型进行可靠编程

如果其他开发人员将使用你的enum代码,你需要提供相关说明,告诉开发人员将新元素添加到任何enum类型时,它们的代码对应的响应是什么。

功能说明:在此例中,声明了一个枚举names。两个枚举数被显式转换为整数并赋给整型变量。

程序清单4-6

using System;

public class Enum_Test

{

    enum names { mary = 8,tom, jack, jenefer };

    static void Main()

    {

        int x = (int)names.mary; int y = (int)names.jenefer;

        Console.WriteLine("mary = {0}", x);

        Console.WriteLine("jenefer = {0}", y);

    }

}

运行结果如图4-6所示。

图4-6  enum类型进行可靠编程

4.1.2.7  值类型介绍——float类型

1.float类型的定义

float关键字表示存储32位浮点值的简单类型,该类型的存储值如表4-5所示。

表4-5  float类型

   

   

   

   

float

± 1.5 × 10 - 45 to ± 3.4 × 1038

7

System.Single

2.float类型的标识

默认情况下,赋值运算符右侧的实数被视为double。因此,应使用后缀f或F初始化浮点型变量,如下所示:

float x = 3.5F;

注意

如果在以上声明中不使用后缀,则会因为你试图将一个double值存储到float变量中而发生编译错误。

3.float类型的转换

可在一个表达式中兼用数值整型和浮点型。在此情况下,整型将转换为浮点型。根据以下规则计算表达式:

— 如果其中一个浮点型为double,则表达式的计算结果为double类型,在关系表达式或布尔表达式中为bool类型。

— 如果表达式中不存在double类型,则表达式的计算结果为float类型,在关系表达式或布尔表达式中为bool类型。

浮点表达式可以包含下列值集:

— 正零和负零

— 正无穷和负无穷

— 非数字值(NaN)

— 有限的非零值集

功能说明:在下面的示例中,包含intshort和float类型的数学表达式得到一个float结果。请注意,表达式中没有double

程序清单4-7

using System;

class float_mixed_Test

{

    static void Main()

    {

        int x = 2;

        float y = 6.5f;

        short z = 11;

        Console.WriteLine("最后的结果是: {0}", x * y / z);

    }

}

输出结果如图4-7所示。

图4-7  float类型转换

4.1.2.8  值类型介绍——int类型

1.int类型的定义

int关键字表示一种整型,该类型的存储值如表4-6所示。

表4-6  int类型

   

   

   

   

int

- 2,147,483,648 2,147,483,647

有符号 32 位整数

System.Int32

2.int类型的标识

可以声明并初始化int类型的变量,例如:

int i = 123;

注意

如果整数没有后缀,则其类型为以下类型中可表示其值的第一个类型:int、uintlong、ulong。在此例中为int类型。

3.int类型的转换

存在从int到longfloatdoubledecimal的预定义隐式转换。例如:

float f = 133;

存在从sbytebyteshortushortchar到int的预定义隐式转换。例如,如果不进行强制转换,下面的赋值语句将产生编译错误。

long aLong = 42;

int i1 = aLong;          // 这个语句是错误的,需要做强制转换

int i2 = (int)aLong;    //经过强制转换后, 表达式是正确的

注意

不存在从浮点型到int类型的隐式转换。例如,除非使用显式强制转换,否则以下语句将生成一个编译器错误:

int x = 5.0;             // 这个表达式是错误的,不存在浮点型到int的隐形转换

int y = (int)5.0;   //强制转换后,表达式是正确的

4.1.2.9  值类型介绍——long类型

1.long类型的定义

long关键字表示一种整型,该类型的存储值如表4-7所示。

表4-7  long类型

   

   

   

   

long

- 9,223,372,036,854,775,808 9,223,372,036,854,775,807

有符号 64 位整数

System.Int64

2.long类型的标识

可以声明并初始化long类型的变量,例如:

long long1 = 4294967296;

注意

如果整数没有后缀,则其类型为以下类型中可表示其值的第一个类型:intuint、long、ulong。在上例中,它是long类型,因为它超出了uint的范围。

还可以像下面这样,在long类型中使用后缀L:

long long2 = 4294967296L;

当使用后缀L时,将根据整数的大小确定它的类型为long还是ulong。在此例中,它是long,因为它小于ulong的范围的下限。

3.long类型的转换

存在从long到floatdoubledecimal的预定义隐式转换。其他情况下必须使用显式转换。例如,不使用显式类型转换时,下列语句将产生编译错误:

int x = 6L;        //不可以从long到int的转换

int x = (int)6L;   //long类型到int类型必须经过强制转换

存在从sbytebyteshortushortintuintchar到long的预定义隐式转换。

注意

不存在从浮点型到long类型的隐式转换。

例如,除非使用显式强制转换,否则以下语句将生成一个编译器错误:

long x =4.0;          // 不可以从浮点型到long的转换

long y = (long)4.0;   //必须强制转换才可以

4.1.2.10  值类型介绍——sbyte类型

1.sbyte类型的定义

sbyte关键字代表一种整型,该类型的存储值如表4-8所示。

表4-8  sbyte类型

   

   

   

   

sbyte

- 128 ~ 127

有符号的 8 位整数

System.Sbyte

2.sbyte类型的标识

可如下例所示声明并初始化sbyte类型的变量:

sbyte sbyte1 = 127;

注意

在以上声明中,整数127从int隐式转换为sbyte。如果整数超出了sbyte的范围,将产生编译错误。

3.sbyte类型的转换

存在从sbyte到shortintlongfloatdoubledecimal的预定义隐式转换。不能将存储范围更大的非文本数值类型隐式转换为sbyte类型。

例如:

  sbyte x = 10, y = 20;

注意

不存在从浮点型到sbyte类型的隐式转换。

例如,除非使用显式强制转换,否则以下语句将生成一个编译器错误:

sbyte x = 3.0;           // 转换错误

sbyte y = (sbyte)3.0;   // 强制转换后,正确

4.1.2.11  值类型介绍——short类型

1.short类型的定义

short关键字代表一种整型数据类型,该类型的存储值如表4-9所示。

表4-9  short类型

   

   

   

   

short

- 32 768~32 767

有符号的 16 位整数

System.Int16

2.short类型的标识

可如下例所示声明并初始化short类型的变量:

short x = 32767;

注意

在以上声明中,整数32 767从int隐式转换为short。如果整数的长度超过了short存储位置的大小,则将产生编译错误。

3.short类型的转换

存在从short到intlongfloatdoubledecimal的预定义隐式转换。不能将存储更大的非文本数值类型隐式转换为short。

例如:

short x = 5, y = 12;

short z = x + y;                    // 转换错误

short z = ( short )(x + y);        // 强制转换正确

short x = 5.0;                          // 转换错误

short y = (short)5.0;              // 强制转换正确

注意

不存在从浮点型到short的隐式转换。例如,除非使用显式强制转换,否则以下语句将生成一个编译器错误。

4.1.2.12  值类型介绍——struct类型

struct类型是一种值类型,通常用来封装小型相关变量组,例如,商品的特征。下面的示例显示了一个简单的结构声明。

public struct Book

{

    public decimal price;     //价格

    public string title;      //题目

    public string author;     //作者

}

结构还可以包含构造函数常量字段方法属性索引器运算符事件嵌套类型,但如果同时需要上述几种成员,则应当考虑改为使用类作为类型。

结构可以实现接口,但它们无法继承另一个结构。因此,结构成员无法声明为protected。

4.1.2.13  值类型介绍——uint类型

1.uint类型的定义

uint关键字表示一种整型,该类型的存储值如表4-10所示。

表4-10  uint类型

   

   

   

   

uint

0 4 294 967 295

无符号 32 位整数

System.UInt32

2.uint类型的标识

可以声明并初始化uint类型的变量,例如:

uint myUint = 4294967290;

注意

如果整数没有后缀,则其类型为以下类型中可表示其值的第一个类型:int、uint、longulong。在此例中,它是uint。

uint uInt1 = 133;

还可以像下面这样使用后缀u或U:

uint uInt2 = 133U;

3.uint类型的转换

存在从uint到longulongfloatdoubledecimal的预定义隐式转换。

例如:float myFloat = 4294967290;   //转换是正确的

注意

存在从byteushortchar到uint的预定义隐式转换。否则必须使用显式转换。例如,如果不进行强制转换,下面的赋值语句将产生编译错误。

uint x = 5.0;            //转换错误,不支持浮点到uint的转换

uint y = (uint)5.0;     //强制转换是正确的

4.1.2.14  值类型介绍——ulong类型

1.ulong类型的定义

ulong关键字表示一种整型,该类型的存储值如表4-11所示。

表4-11  ulong类型

   

   

   

   

ulong

0~18 446 744 073 709 551 615

无符号 64 位整数

System.UInt64

2.ulong类型的标识

可以声明并初始化ulong类型的变量,例如:

ulong uLong = 9223372036854775808;

注意

如果整数没有后缀,则其类型为以下类型中可表示其值的第一个类型:intuintlong、ulong。在上面的示例中,它是ulong类型。

还可根据以下规则使用后缀指定文字类型:

— 如果使用L或l,那么根据整数的大小,可以判断出其类型为long还是ulong。

— 如果使用U或u,那么根据整数的大小,可以判断出其类型为uint还是ulong。

— 如果使用UL、ul、Ul、uL、LU、lu、Lu或lU,则整数的类型为ulong。

例如,以下三个语句的输出将为系统类型Uint64,此类型对应于别名ulong:

Console.WriteLine(9223372036854775808L.GetType());

Console.WriteLine(123UL.GetType());

Console.WriteLine((123UL + 456).GetType());

3.ulong类型的转换

存在从ulong到floatdoubledecimal的预定义隐式转换。

不存在从ulong到任何整型的隐式转换。例如,不使用显式类型转换时,下列语句将产生编译错误:

long long1 = 6UL;   // 转换错误,不存在从 ulong 到任何整型的隐式转换

存在从byteushortuintchar到ulong的预定义隐式转换。

同样,不存在从浮点型到ulong类型的隐式转换。例如,除非使用显式强制转换,否则以下语句将生成一个编译器错误:

ulong x = 5.0; // 转换错误,不存在从浮点型到 ulong 类型的隐式转换

ulong y = (ulong)5.0; // 强制转换正确

4.1.2.15  值类型介绍——ushort类型

1.ushort类型的定义

ushort关键字表示一种整数数据类型,该类型的存储值如表4-12所示。

表4-12  ushort类型

   

   

   

   

ushort

0~65 535

无符号 16 位整数

System.UInt16

2.ushort类型的标识

可以声明并初始化ushort类型的变量,例如:

ushort myShort = 65535;//超出范围

注意

在以上声明中,整数65 535从int隐式转换为ushort。如果整数超出了ushort的范围,将产生编译错误。

3.ushort类型的转换

存在从ushort到intuintlongulongfloatdoubledecimal的预定义隐式转换。

存在从bytechar到ushort的预定义隐式转换。其他情况下必须使用显式转换。例如,请看以下两个ushort变量x和y:

ushort x = 4, y = 13;

以下赋值语句将产生一个编译错误,原因是赋值运算符右侧的算术表达式在默认情况下的计算结果为int类型。

ushort z = x + y; 

若要解决此问题,请使用强制转换:

ushort z = (ushort)(x + y);   //使用强制转换

但是,在目标变量具有相同或更大的存储时,使用下列语句是可能的:

int m = x + y;

long n = x + y;

4.1.3  引用类型包括的内容

引用类型的变量又称为对象,可存储对实际数据的引用。

C#的引用类型包括class(类)、delegate(委托)、interface(接口)、object、string组成,本章先介绍一下object引用类型,其他引用类型会在其他章节重点介绍。

C#引用类型——object类型

1.object类型的定义

在C#的统一类型系统中,所有类型包括预定义类型、用户定义类型、引用类型和值类型等都是直接或间接从Object继承的。可以将任何类型的值赋给object类型的变量。

装箱和取消装箱使值类型能够被视为对象。对值类型来说,装箱是将该值类型打包到Object引用类型的一个实例中,这使得值类型可以存储于垃圾回收堆中。而取消装箱则是将从对象中提取值类型。

功能说明:示例演示了object类型的变量如何接收任何数据类型的值,以及object类型的变量如何在.NET Framework中使用Object的方法。

程序清单4-8

using System;

class obj_Sample_Class

{

    public int i = 10;

}

class MainClass

{

    static void Main()

    {

        object a;

        a = 100;

        Console.WriteLine(a);

        Console.WriteLine(a.GetType());

        Console.WriteLine(a.ToString());

        a = new obj_Sample_Class();

        obj_Sample_Class classRef;

        classRef = (obj_Sample_Class)a;

        Console.WriteLine(classRef.i);

    }

}

运行结果如图4-8所示。

图4-8  object类型的定义

2.“装箱”的概念

在C#的统一类型系统中,所有类型(预定义类型、用户定义类型、引用类型和值类型)都是直接或间接从Object继承的。将值类型的变量转换为对象的过程称为“装箱”。

3.“取消装箱”的概念

将对象类型的变量转换为值类型的过程称为“取消装箱”。

4.C#做“装箱”转换工作

装箱用于在垃圾回收堆中存储值类型。装箱是值类型到object类型或到此值类型所实现的任何接口类型的隐式转换。对值类型装箱会在堆中分配一个对象实例,并将该值复制到新的对象中。

请看以下值类型变量的声明:

int i = 123;

以下语句对变量i隐式应用装箱操作:

object o = i;  // 装箱操作

此语句的结果是在堆栈上创建对象引用o,而在堆上则引用int类型的值。该值是赋给变量i的值类型值的一个副本。

功能说明:此示例通过装箱将整数变量i转换为对象o。该示例表明原始值类型和装箱的对象使用不同的内存位置,因此能够存储不同的值。

程序清单4-9

using System;

class boxing_Test

{

    static void Main()

    {

        int i = 100;

        object o = i;  // 装箱

        i = 200;

        System.Console.WriteLine("直接赋值的数据= {0}", i);

        System.Console.WriteLine("装箱后的数据= {0}", o);

    }

}

运行结果如图4-9所示。

图4-9  C#做“装箱”转换工作

5.C#做“装箱取消”转换工作

取消装箱是从object类型到值类型或从接口类型到实现该接口的值类型的显式转换。取消装箱操作包括:

— 检查对象实例,确保它是给定值类型的一个装箱值。

— 将该值从实例复制到值类型变量中。

以下语句同时说明了装箱和取消装箱操作:

int i = 123;      // a value type

object o = i;     // boxing

int j = (int) o;  // unboxing

注意

要在运行时成功取消装箱值类型,被取消装箱的项必须是对一个对象的引用,该对象是先前通过装箱该值类型的实例创建的。尝试对null或对不兼容值类型的引用进行取消装箱操作,将导致InvalidCastException。

功能说明:下面的示例演示无效的取消装箱及引发的InvalidCastException。使用try和catch,在发生错误时显示错误信息。

程序清单4-10

using System;

class Unboxing_Test

{

    static void Main()

    {

        int i = 100;

        object o = i;  // 装箱

        try

        {

            int j = (short) o;  // 取消装箱           

            System.Console.WriteLine("取消装箱成功.");

        }

        catch (System.InvalidCastException e)

        {

            System.Console.WriteLine("{0} 取消装箱异常.", e.Message);

        }

    }

}

运行结果如图4-10所示。

图4-10  C#做“装箱取消”转换工作

如果将下列语句:

int j = (int) o;

功能说明:被取消装箱的项必须是对一个对象的引用。

程序清单4-11

using System;

class Unboxing_Test

{

    static void Main()

    {

        int i = 100;

        object o = i;  // 装箱

        try

        {

            int j = (int)o;  // 取消装箱           

            System.Console.WriteLine("取消装箱成功.");

        }

        catch (System.InvalidCastException e)

        {

            System.Console.WriteLine("{0} 取消装箱异常.", e.Message);

        }

    }

}

运行结果如图4-11所示。

图4-11  被取消装箱的项是对一个对象的引用

posted on 2008-09-05 22:26 死神 阅读(1247) 评论(0)  编辑  收藏 所属分类: C#学习


只有注册用户登录后才能发表评论。


网站导航:
 

导航

统计

公告

欢迎大家来到我的个人世界!

常用链接

留言簿(3)

随笔分类(5)

随笔档案(9)

文章分类(37)

文章档案(41)

相册

语音技术

最新随笔

搜索

积分与排名

最新评论

阅读排行榜

评论排行榜