装箱(boxing)和拆箱(unboxing)是C#中的重要概念。它允许将任何类型的数据转换成对象类型,同时也允许任何类型的对象转换到与之兼容的数据类型。必须注意的是:装箱和拆箱过程中必须遵循类型兼容的原则,否则会转换失败。
装箱转换是指将一个值类型的数据隐式的转换成一个对象(object)的数据。把一个值类型装箱,就是创建一个object类型的实例,并把该值类型的值复制给该object:
int k=100;
object obj=k;
上面的两条语句中,第一条语句先声明一个整形变量k并对其赋值,第二条语句则先创建一个object类型的实例obj,然后将k的值赋给obj。
在装箱转换时,也可以使用显示转换,如:
int k=100;
object obj=(object)k;
这样做是合法的,但是没有必要。
和装箱相反,拆箱转换是指将一个对象类型的数据显式地转换成一个值类型的数据。
拆箱操作分为两步:首先检查对象实例,确保它是给定值类型的一个装箱值,然后把实例的值复制到值类型的数据中:
object obj=228;
int k=(int)obj;
上面的两条语句中,首先会检查obj这个object实例的值是否为给定值类型的装箱值,由于obj的值为228,给定的值类型为整形,所以满足拆箱转换的条件,会将obj的值复制给整形变量k。从上面的第二条语句可以看出:拆箱转换需要(而且必须)执行显示转换,这是它与装箱操作的不同之处。
异常就是程序运行的过程中发生的错误或意想不到的状态。如溢出、被零除、数组下标超出界限以及内存不够等。所有异常类都是Exception的子类。
下面介绍几个异常类:
try
{
//语句块
}
catch (异常对象声明1)
{
//语句块1
}
catch (异常对象声明2)
{
//语句块2
}
有时候,需要捕获所有的异常,而不管它是什么类型,这时候就需要使用不带参数的catch语句了。
使用throw语句抛出异常,要注意再throw语句中如何使用new来创建DivideByZeroException异常,因为throw抛出的是对象。
在finally语句中不能使用break、continue、goto等语句把控制转移到finally语句之外。
数组的初始化分为两种,动态初始化和静态初始化。
动态初始化,需要借助new运算符,为数组元素分配内存空间,并为数组元素赋初值,格式如下:
数组名=new 数据类型[数组长度]
可以合并起来,如:int[] IntArr=new int[5];垢面没有数值的情况下,默认复制为0,
int[] IntArr=new int[5]{3,9,6,4,5};这种情况就是动态初始化。
静态初始化需要说明几点,和动态初始化不同的是,静态初始化数组必须与数组定义放在同一条语句当中,否则程序就会出错:
int[] IntArr;
IntArr={3,6,9,12,34};//错误
引用参数:在C#中用ref修饰符来声明参数为引用参数。引用参数本身并不创建存储空间,而是将实参的存储地址传递给形参。可以认为引用参数就是调用方法时给出的变量,而不是一个新变量。在函数调用中引用参数必须被赋初值。在调用时,传送给ref的参数的必须是变量,类型也必须相同,并且必须使用ref修饰符:
public void Swap(ref int x, ref int y)
{
int k;
k = x;
x = y;
y = k;
}
static void Main()
{
int a = 8, b = 68;
Console.WriteLine("a={0},b={1}", a, b);
Welcome sw = new Welcome();
sw.Swap(ref a, ref b);
Console.WriteLine("a={0},b={1}", a, b);
}
在C#里面用out修饰符定义的参数称为输出参数。如果希望方法有多个返回值,可使用输出参数。输出参数与引用参数类似,它不产生新的存储空间。重要的差别在于:out参数在传入之前,可以不赋值;在方法体内,out参数必须被赋值。在调用时,传送给out参数的必须是变量,类型必须相同,并且必须使用out修饰:
public class MyClass
{
public string TestOut(out string i)
{
i = "使用out关键字";
return "out参数";
}
public static void Main()
{
string x;
MyClass app = new MyClass();
Console.WriteLine(app.TestOut(out x));
Console.WriteLine(x);
}
}
对于一个类的众多对象,如果能为对象标上下标,访问对象就会很方便。C#提供了索引指示器(indexer),通过给对象编写索引指示器,就能像范围数组元素一样访问对象。它的引入也是为了使编写的程序更加直观、简洁、易于理解,它以访问数组的方法来访问类对象。
委托,顾名思义就是代理人的意思。通俗的讲,委托是一个可以引用方法的对象,当创建一个委托,也就创建了一个引用方法的对象,进而就可以调用那个方法,即委托可以调用它所指向的方法。
使用委托可以将方法应用(不是方法)封装在委托对象中,然后将委托对象传递给调用方法的代码,这样编译的时候代码就没有必要知道调用那个方法。通过使用委托程序能够在运行时动态的调用不同的方法,而且委托引用的方法可以改变,这样同一个委托就可以调用多个不同的方法。
C#中使用委托的具体步骤是:
using System;
delegate int MyDelegate();
class MyClass
{
public int M1()
{
Console.WriteLine("调用的是实例的方法");
return 0;
}
public static int M2()
{
Console.WriteLine("调用的是静态的方法");
return 0;
}
}
class Test
{
static void Main()
{
MyClass w = new MyClass();
MyDelegate p = new MyDelegate(w.M1);
p();
p = new MyDelegate(MyClass.M2);
p();
}
}
委托对象可以封装多个方法,这些方法的集合称为调用列表。委托使用“+”,“+=”,“-”,“-=”运算符向调用列表中增加或移除方法。委托加减运算后的结果,如果其中不包含方法,则结果为null;
///
MyClass my = new MyClass();
MyDelegate a = new MyDelegate(my.M1);
MyDelegate b = new MyDelegate(MyClass.M2);
MyDelegate c = a + b;
c();
c -= a;
c -= b;//此时c的值为null