继续上回,数组是我们经常用到的,我来介绍一下:数组是具有相同类型的一组数据。当访问数组中的数据时,可以通过下标来指明。c#中数组元素可以为任何数据类型,数组下标从0开始,即第一个元素对应的下标为0,以后逐个递增。数组可以一维也可多维。
//包含6个元素的一维整数数组;
int[] mf1=new int[6]; //注意初始化数组的范围,或者指定初值;
//包含6个元素的一维整数数组,初值1,2,3,4,5,6
int[] mf2=new int[6](1,2,3,4,5,6);
//一维字符串数组,如果提供了初始值设定项,则还可以省略 new 运算符
string[] mf3={"c","c++","c#"};
//一维对象数组
Object[] mf4 = new Object[5] { 26, 27, 28, 29, 30 };
//二维整数数组,初值mf5[0,0]=1,mf5[0,1]=2,mf5[1,0]=3,mf5[1,1]=4
int[,] mf5=new int[,]{{1,2},{3,4}};
//6*6的二维整型数组
int[,] mf6=new mf[6,6];
下面来看一个一维字符串数组的遍历
using System;
public class MikeCat
{
static void PrintArray(string[] arr)
{
//打印数组元素,arr.Length 表示数组元素的个数
for(int i=0;i<arr.Length;i++)
{
Console.WriteLine("arr[{0}]={1}",i,arr[i]);
}
}
public static void Main()
{
string[] arr={"c","c++","c#"};
//将数组作为一个参数传递
PrintArray(arr);
}
}
程序结果:arr[0]=c arr[1]=c++ arr[2]=c#
下面来看一个4行2列(4*2)的整型数组的遍历:
using System;
public class MikeCat
{
static void PrintArray(int[,] arr)
{
//通过两次FOR循环遍历二维数组
for(int i=0;i<4;i++)//初始化i作为循环变量,i++实现该变量的自增运算。
//for循环满足条件后执行完循环体一次后执行i++,然后进入下次循环。简单的c语法,这里做简单介绍照顾初学者。(详细可参阅谭浩强先生的c语言程序设计一书)
{
for(int j=0;j<2;j++)
{
Console.WriteLine("arr[{0},{1}]={2}",i,j,arr[i,j]);//打印每个二维数组元素
}
}
}
public static void Main()
{
//主函数
//将数组作为一个参数传递
PrintArray(new int[,]{{1,2},{3,4},{5,6},{7,8}};
}
}
运行结果:arr[0,0]=1 arr[0,1]=2 arr[1,0]=3 arr[1,1]=4 arr[2,0]=5 arr[2,1]=6 arr[3,0]=7 arr[3,1]=8
类是面向对象程序设计的基本构造块,详细我们在后面介绍。这里我们介绍两个特殊的类,即object类和string类
1.object类
object类是预定义类System.Object的别名,它是所有其他类型的基类。c#中所有类型都直接或间接从object类中继承。因此,一个object类的变量可以赋予任何类型的值。
int i=30;
object obj1;
obj1=i;
object obj2='a';
2.string类
string类专门用于对字符串的操作,他是预定义类System.String的别名
string str1="mikecat";
可以用"+"号连接两个字符串。
string str2="username:"+"mikecat";
如果访问单个字符,则要用下标。
char c=str1[0];
比较两个字符串是否相等,可用比较操作符"=="//有别于basic语法
bool b=(str1==str2);
c#中,取消了c和c++中使用最灵活,也是最难掌握的指针。那么在c#中如何提供c/c++中的函数指针的功能?c#提供了委托(delegate),委托是继承自System.Delegate类的引用类型。它相当于函数指针原型。与函数指针不同的是,委托在c#中是类型安全的,委托特别适合于匿名调用。要使用委托需经过三个步骤,即声明、实例化、调用。
using System;
//声明一个名为mfDelegate的委托,该委托有一个string类型的参数
//c#编译器编译时会产生一个新类,该类继承自System.Delegate,类
//名为mfDelegate
public delegate void mfDelegate(string name);
public class MikeCat
{
//定义与mfDelegate有相同参数类型的方法Hello()
public static void Hello(string name)
{
Console.WriteLine("您好,{0}!",name);
}
//定义与mfDelegate有相同参数类型的方法GoodBye()
public static void GoodBye(string name)
{
Console.WriteLine("再见,{0}!",name);
}
public static void Main()
{
//创建一个mfDelegate实例 mf1
mfDelegate mf1=new mfDelegate(Hello);
//调用mf1
mf1("mikecat");
mfDelegate mf2=new mfDelegate(GoodBye);
mf2("mikecat");
//将mf1 mf2组合成一个新的委托mf3
mfDelegate mf3=mf1+mf2;
//调用mf3
mf3("迈克老猫");
//从组合的委托mf3中删除mf1
mfDelegate mf4=mf3-mf1;
mf4("mikecat");
}
}
程序结果:您好,mikecat!//mf1; 再见,mikecat!//mf2
您好,迈克老猫! 再见,迈克老猫!//mf3
再见,mikecat!//mf4
这次我们首先讲解一下类型转换,我们在写程序时经常用到类型转换,而且特别多的规则。我在这里粗略的讲解一下。
隐式转换是系统默认的、不需要加以声明即可进行的转换。
1.隐式数值转换
隐式数值转换实际上就是从低精度的数值类型转换到高精度的数值类型的转换。
byte x=255;ushort y=x;y=65535;float z=y;//均从低精度到高精度,反之会产生溢出
隐式数值转换的类型太多,我就不多介绍,记住上面的原则就可以了。详细规则可查看msdn
2.隐式枚举转换
隐式枚举转换用于把十进制整数0转换成任何枚举类型,对应的其他整数则不存在这种转换。
using System;
enum Color
{
Red,Green,Blue
};
class MikeCat
{
static void Main()
{
Color c;//声明Color的变量c;
c=0;//将0转换为Red;
Console.WriteLine("c的值是{0}",c);//结果:c的值是Red;如果将c=0改成c=1,则编译器会给出错误。
}
}
3.隐式引用转换
从任何引用类型到object的转换。
从类类型A到类类型B的转换,其中类A从类B派生得到。
从类类型A到接口类型B的转换,其中类A实现了接口B。
从接口类型A到接口类型B的转换,其中接口A是从接口B派生。
从任何数组类型到System.Array的转换。
从任何委托类型到System.Delegate的转换。
从任何数组类型或委托类型到System.ICloneable的转换。
从空类型(null)到任何引用类型的转换。
显示转换也称为强制转换,它需要用户明确地指定转换的类型。
char c=(char)65;//A
int i=(int)'A';//65
显示转换包含所有的隐式转换,即任何系统允许的隐式转换写成显示转换的形式都是允许的。
int i=300;
long l=(long)i;
另外一例:
using System;
class MikeCat
{
static void Main()
{
long longValue = Int64.MaxValue;
int intValue = (int) longValue;
Console.WriteLine("(int){0} = {1}", longValue, intValue);
}
}
类型 long 转换为 int 是显式转换,它使用了强制转换表达式。输出为:
(int) 9223372036854775807 = -1这是因为有溢出发生。
1.显示数值转换
显示数值转换是指当不存在相应的隐式转换时从一种数值类型转换为另一种数值类型。转换类型也很繁琐,只需记住转换规则,详细查阅MSDN。由于显示数值转换可能丢失信息或引发异常,因此转换按以下原理被处理:简略说就是高精度显示转换为低精度会引发异常(OverFlowException),未引发异常的情况,源变量的值通过舍入得到最接近的整型值作为转换结果。详细转换时的异常情况查阅MSDN
/*test.cs*/
using System;
public class MikeCat
{
public static void Main()
{
ushort u=65535;
byte b=(byte)u;
Console.WriteLine("b的值是{0}",b);
}
}
编译状况如下:
E:">csc test.cs
Microsoft (R) Visual C# .NET 编译器版本 7.10.3052.4
用于 Microsoft (R) .NET Framework 版本 1.1.4322
版权所有 (C) Microsoft Corporation 2001-2002。保留所有权利。
E:">test.exe
b的值是255
E:">csc/checked test.cs ///checked[+|-] 生成溢出检查
E:">test.exe
未处理的异常: System.OverflowException: 算术运算导致溢出。
at MikeCat.Main()
E:">csc/checked- test.cs
E:">test.exe
b的值是255
2.显示枚举转换
显示枚举转换其实就是将枚举类型的元素类型与相应类型之间进行隐式显示转换。比如,有一个元素类型int的枚举类型E,当执行从E到byte的显示枚举转换时,实际执行的是从int到byte的显示数值转换。
using System;
enum Color
{
Red,Green,Blue
};
public class MikeCat
{
static void Main()
{
Color c;//声明Color的变量c;
c=(Color)4;//对数字3进行显示枚举转换
Console.WriteLine("c的值是{0}",c);
}
}
结果:c的值是4
Convert 类
将一个基本数据类型转换为另一个基本数据类型。
该类返回值与指定类型的值等效的类型。受支持的基类型是 Boolean、Char、SByte、Byte、Int16、Int32、Int64、UInt16、UInt32、UInt64、Single、Double、Decimal、DateTime 和 String。
存在将每个基类型转换为每个其他基类型的转换方法。不过,所执行的实际转换操作分为三类:
从某类型到它本身的转换只返回该类型。不实际执行任何转换。
无法产生有意义的结果的转换引发 InvalidCastException。不实际执行任何转换。下列转换会引发异常:从 Char 转换为 Boolean、Single、Double、Decimal 或 DateTime,以及从这些类型转换为 Char。下列转换会引发异常:从 DateTime 转换为除 String 之外的任何类型,以及从任何类型(String 除外)转换为 DateTime。
任何基类型(上面描述的基类型除外)都可以与任何其他基类型进行相互转换。
如果数字类型转换导致精度丢失(即某些最低有效位丢失),不引发异常。但是,如果结果超出了特定转换方法的返回值类型所能表示的范围,则将引发异常。
下面介绍一下和类型转换相关的装箱、取消装箱
装箱是值类型到 object 类型或到该值类型所实现的任何接口类型的隐式转换。将一个值的值装箱会分配一个对象实例并将该值复制到新的对象中。
请看以下值类型变量的声明:
int i = 123;
以下语句对变量 i 隐式应用装箱操作:
object o = i;
此语句的结果是在堆栈上创建对象 o,而该对象在堆上引用 int 类型的值。该值是赋给变量 i 的值类型值的一个副本。下图说明了两个变量 i 和 o 之间的差异。
装箱转换
在堆栈上 在堆上
i 123
int i=123;
o (将i装箱)
object o=i; int 123
也可以(但绝不必要)如下例所示显式执行装箱:
int i = 123;
object o = (object) i;
示例
此例将整数变量 i 通过装箱转换为对象 o。这样,存储在变量 i 中的值就从 123 更改为 456。此例显示对象保留了内容的原始副本,即 123。
// boxing.cs
// Boxing an integer variable
using System;
class TestBoxing
{
public static void Main()
{
int i = 123;
object o = i; // Implicit boxing
i = 456; // Change the contents of i
Console.WriteLine("The value-type value = {0}", i);
Console.WriteLine("The object-type value = {0}", o);
}
}
输出
The value-type value = 456
The object-type value = 123
取消装箱
取消装箱是从 object 类型到值类型或从接口类型到实现该接口的值类型的显式转换。取消装箱操作包括:
检查对象实例,确保它是给定值类型的一个装箱值。
将该值从实例复制到值类型变量中。
以下语句同时说明了装箱和取消装箱操作:
int i = 123; // A value type
object box = i; // Boxing
int j = (int)box; // Unboxing
下图显示了以上语句的结果。
取消装箱转换
在堆栈上 在堆上
i 123
int i=123;
o (将i装箱)
object o=i; int 123
j 123
int j=(int) o;
为使到给定值类型的取消装箱转换在运行时取得成功,源参数的值必须是对某个对象的引用,而该对象先前是通过将该值类型的值装箱创建的。如果源参数为 null 或是对一个不兼容对象的引用,则会引发 InvalidCastException。
示例
下面的示例阐释无效取消装箱的情况,即错误的取消装箱如何导致 InvalidCastException。通过使用 try 和 catch,发生错误时会显示错误信息。
using System;
public class UnboxingTest
{
public static void Main()
{
int intI = 123;
// Boxing
object o = intI;
// Reference to incompatible object produces InvalidCastException
try
{
int intJ = (short) o;
Console.WriteLine("Unboxing OK.");
}
catch (InvalidCastException e)
{
Console.WriteLine("{0} Error: Incorrect unboxing.",e);
}
}
}
输出
System.InvalidCastException
at UnboxingTest.Main() Error: Incorrect unboxing.
如果将下列语句:
int intJ = (short) o;
更改为:
int intJ = (int) o;
转换将执行,而您将得到输出“Unboxing OK”。