C#委托和事件(1)

本章将讲述.NET框架中的部分高级特性。对这些高级特的掌握性体现了应聘者对.NET运行机制的理解程度,所以在面试考题中经常出现。

7.1  委托和事件(1)

委托和事件一直被视为C#的难点,.NET的面试题中经常出现这些知识点。本节通过常见的面试考题辅以典型实例剖析,对知识点深度讲解。

面试例题1:举例说明如何使用C#中的委托?

考点:委托的含义,委托和引用方法的联系。

出现频率:★★★★★

解答

本实例通过用户选择不同格式显示输入的文字,解决办法是首先建立委托类型,其签名可以匹配多个格式化字符,然后在Main()方法中创建委托对象,通过判断用户的输入,将委托对象进行相应地初始化,从而完成不同方法的引用。在目录下新建一个程序文件,并命名为DelegateTest.cs,编写代码如代码7.1所示。

代码7.1  简单使用C#的委托:DelegateTest.cs

using System;
namespace NET.CHP6
{
public class DelegateTest
{
//定义一个MyDel委托类型,其签名接收两个string类型参数,返回类型也为string
public delegate string MyDel(string nm, string pwd);       
static void Main(string[] args)
{
//声明MyDel类型的md变量
MyDel md;
Console.WriteLine("请输入2个参数,并用逗号分隔");
//将用户输入值赋值给InputValue变量
string InputValue = Console.ReadLine();
//获取英文逗号在InputValue变量中的索引值,并赋值给Pos变量
int Pos = InputValue.IndexOf(",");
//将英文逗号前面部分的子字符串赋值给ValueA变量
string ValueA = InputValue.Substring(0, Pos);
//将英文逗号后面部分的子字符串赋值给ValueB变量
string ValueB = InputValue.Substring(Pos + 1);
Console.WriteLine("请输入A,B,C,D,以确定所调用方法");
//将用户输入值转换为大写,并赋值给InputMethod方法
string InputMethod = Console.ReadLine().ToUpper();
//判断InputMethod变量的值
switch (InputMethod)
{
case "A":
//如果用户输入为A或a,则创建MyDel委托对象,
其引用变量为md,指向formatA方法
md = new MyDel(formatA);
break;
case "B":
//如果用户输入为B或b,则创建MyDel委托对象,
其引用变量为md,指向formatB方法
md = new MyDel(formatB);
break;
case "C":
//如果用户输入为C或c,则创建MyDel委托对象,
其引用变量为md,指向Another类的formatC静态方法
md = new MyDel(Another.formatC);
break;
case "D":
//如果用户输入为D或d,则首先创建创建Another对象,引用为ano变量
//然后创建MyDel委托对象,其引用变量为md,指向ano对象的formatD方法
Another ano = new Another();
md = new MyDel(ano.formatD);
break;
default:
//其他情况下,创建MyDel委托对象,其引用变量为md,指向formatA方法
md = new MyDel(formatA);
break;
}
//调用md委托对象,将返回值赋值给result变量
string result = md(ValueA, ValueB);
Console.WriteLine("\n\t==========以下为委托方法执行结果==========");
//输出result变量值
Console.WriteLine(result);
}
//定义两个静态方法formatA和formatB,符合MyDel委托类型的签名
static string formatA(string a, string b)
{
string words = "I am the first static method.
\nMy name is " + a + "\nMy password is " + b;
words += "\n我是第一个静态方法。\n我的名字是:
" + a + "\n我的密码是: " + b;
return words;
}
static string formatB(string a, string b)
{
string words = "I am the second static method
.\nMy name is " + a + "\nMy password is " + b;
words += "\n我是第二个静态方法。\n我的名字是:
" + a + "\n我的密码是: " + b;
return words;
}
}
//定义外部类,其内含静态方法和实例方法符合MyDel委托类型签名
class Another
{
internal static string formatC(string a, string b)
{
string words = "I am the third static method,
I belong to Another class.\nMy name is " + a + "\nMy password is " + b;
words += "\n我是第三个静态方法,我属于 Another 类。
\n我的名字是: " + a + "\n我的密码是: " + b;
return words;
}
internal string formatD(string a, string b)
{
string words = "\n我是1个实例方法,我所属的对象实
例是 Another 类所构造的。\n我的名字是: " + a + "\n我的密码是: " + b;
return words;
}
}
}

在Main()方法以外定义了1个委托类型,其名称为MyDel,其返回值为String类型,并接收2个String类型的参数。另外还声明了2个静态方法和1个类,其中Another类含有2个方法,分别为静态方法formatC()和实例方法formatD(),这2个方法都用internal修饰。

在Main()方法中,首先声明MyDel委托类型的对象,并命名为md。通过Console.ReadLine()方法,接收用户的输入并存储到InputValue变量中,通过","将InputValue分隔为2个字符串,分别存储于ValueA和ValueB;然后接收用户的输入并存储于InputMethod变量中,通过switch语句判定用户输入是否为A、B、C、D或其他。不同的InputMethod值通过以下代码语句初始化md的引用:

md = new MyDel(调用方法);

最后直接输出md的方法调用。在命令行下编译DelegateTest.cs,执行DelegateTest程序,程序提示"请输入两个参数,并用逗号分隔"。输入相应的值后,程序再次提示"请输入A,B,C,D,以确定所调用方法",输入"abcd",即4个选择以外的字母,程序运行结果如图7.1所示。

 
(点击查看大图)图7.1  委托执行结果

由上可知,程序中的switch分支语句执行了default条件下的代码,即调用第1个静态方法。再次运行DelegateTest程序,程序提示调用方法时,输入"d",运行结果如图7.2所示。

如果首先输入"YeQing,password"字符串,然后输入"d",程序返回D字母对应的结果。由结果可知,委托类型对象md引用了Anothoer类的实例方法formatD()。

 
(点击查看大图)图7.2  委托执行结果

解析

很多C#书籍介绍过,C#对C++的借鉴过程中去掉了指针部分,但是在学习到C#委托类型的知识点时,很多C++的程序员会想起指针。不过C#中的委托并不完全等同于指针,相对于C++中的指针,委托是面向对象的、类型安全的类型,在编程中使用更加方便、可靠。

说明:CLR能够保证委托指向一个有效的方法,而不会指向无效地址或者越界地址。

可将委托看作一种新的对象类型,委托主要用于.NET Framework中的事件处理程序和回调函数。委托类型可定义一个签名,并且它只能持有与它的签名相匹配的方法引用。所有委托类型对象都有方法调用列表,它是在调用委托对象时所执行方法的一个链接列表。方法调用列表所链接的方法可以是静态方法,也可以是实例方法。对于实例方法,列表中所对应的是一个实例方法和其所属实例,而对于静态方法,列表中只对应一个方法。

说明:列表中的方法即为与委托类型定义签名相匹配的方法。

当委托类型匹配方法的返回类型和参数列表时,这个委托类型即和此方法兼容。另外,方法的名称等特性不需要和委托类型名称匹配。用delegate 关键字可以定义一个委托,通知编译器这是一个委托类型。委托类型声明的形式类似,没有函数体的函数,但是有相应的返回值和参数列表,其格式如以下代码所示:

public delegate 返回类型 委托名称(参数类型1 参数1,参数类型2 参数2,... );
通过委托定义中的返回值类型和参数列表即可匹配其他方法,而委托名称是这种委托类型的名称。delegate关键字定义时,临时定义了一个派生于System.MulticastDelegate类的密封类,这个类与其基类System.Delegate均同为委托提供必要的基础成员。在使用委托时声明该委托类型的对象,然后将这个对象初始化为该委托对象签名匹配的方法引用。其结果是该委托对象调用了相应的方法,这个委托对象也可当作这个方法使用。delegate关键字定义的委托类型名称是MyDel,创建该委托类型的对象,其对象被初始化后拥有方法调用列表,分析过程如图7.3所示。
 
(点击查看大图)图7.3  委托的分析图
posted on 2009-12-25 14:56  米高佐敦  阅读(237)  评论(0编辑  收藏  举报