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

C#知识点详解

2016-06-16 11:17 351 查看

1.装箱与拆箱

装箱(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。从上面的第二条语句可以看出:拆箱转换需要(而且必须)执行显示转换,这是它与装箱操作的不同之处。

2.异常

异常就是程序运行的过程中发生的错误或意想不到的状态。如溢出、被零除、数组下标超出界限以及内存不够等。所有异常类都是Exception的子类。

下面介绍几个异常类:

OutOfMemoryException:当通过new运算符分配内存失败时,将会抛出这个异常。
StackOverflowException:当执行栈中包含太多的待执行方法而导致空间耗尽时,将会抛出该异常。
NullReferenceException:当null引用在造成引用的对象被需要的情况下使用时,将会抛出该异常。
InvalidCastException:在执行从基类型向派生类型显式转换失败时,将会抛出该异常。
ArrayTypeMismatchException:当向数组中保存一个与元素类型不兼容的值时,将会抛出该异常。
IndexOutOfRangeException:当使用超出数组边界的索引时将会抛出该异常。
DivideByZeroException:当除数为0时将会抛出该异常。
SecurityException:当检测到一个安全错误时,将抛出该异常。

C#中用4个关键字:try、throw、catch和finally管理异常处理。把可能出现的异常的程序语句包含在一个try块中,如果try块中出现异常,此异常就会被抛出,使用catch就可以捕获到此异常,并且可以合理的处理异常。C#中运行系统可以自动抛出产生的异常,而使用关键字throw可以人为的抛出异常。如果发生一个异常,一些善后操作可能不会被执行,这时用户可以使用finally语句块来避免这个问题。不管是否抛出异常,finally语句块中的代码都将执行。

try catch语句一般如下:

try
{
//语句块
}
catch (异常对象声明1)
{
//语句块1
}
catch (异常对象声明2)
{
//语句块2
}


有时候,需要捕获所有的异常,而不管它是什么类型,这时候就需要使用不带参数的catch语句了。

使用throw语句抛出异常,要注意再throw语句中如何使用new来创建DivideByZeroException异常,因为throw抛出的是对象。

在finally语句中不能使用break、continue、goto等语句把控制转移到finally语句之外。

3.数组

数组的初始化分为两种,动态初始化和静态初始化。

动态初始化,需要借助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};//错误

4.参数

引用参数:在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);
}
}



5.索引指示器

对于一个类的众多对象,如果能为对象标上下标,访问对象就会很方便。C#提供了索引指示器(indexer),通过给对象编写索引指示器,就能像范围数组元素一样访问对象。它的引入也是为了使编写的程序更加直观、简洁、易于理解,它以访问数组的方法来访问类对象。

6.委托与事件

委托,顾名思义就是代理人的意思。通俗的讲,委托是一个可以引用方法的对象,当创建一个委托,也就创建了一个引用方法的对象,进而就可以调用那个方法,即委托可以调用它所指向的方法。

使用委托可以将方法应用(不是方法)封装在委托对象中,然后将委托对象传递给调用方法的代码,这样编译的时候代码就没有必要知道调用那个方法。通过使用委托程序能够在运行时动态的调用不同的方法,而且委托引用的方法可以改变,这样同一个委托就可以调用多个不同的方法。

C#中使用委托的具体步骤是:

声明一个委托,其参数形式一定要和想要包含的方法的参数形式一样。
定义所有要定义的方法,其参数形式和第一步中生命的委托对象的参数形式必须相同。
创建委托对象并将所希望的方法包含在该委托对象中。
通过委托对象调用包含在其中的各个方法。
格式:【修饰符】delegate 返回类型 委托名(参数列表)

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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: