asp.net笔试题收藏3

来源:互联网 发布:淘宝上买洗衣机可靠吗 编辑:程序博客网 时间:2024/05/16 14:24

问题四 C#中的委托是什么?事件是不是一种委托?

 

 

 

 

 

:

 

 

 

 

 

委托

 

 

 

 

 

委托是C#中的一种引用类型,类似于C/C++中的函数指针。与函数指针不同的是,委托是面向对象、类型安全的,而且委托可以引用静态方法和实例方法,而函数指针只能引用静态函数。委托主要用于 .NET Framework 中的事件处理程序和回调函数。

 一个委托可以看作一个特殊的类,因而它的定义可以像常规类一样放在同样的位置。与其他类一样,委托必须先定义以后,再实例化。

 

 

 

 

 

委托派生于基类System.Delegate,不过委托的定义和常规类的定义方法不太一样。委托的定义通过关键字delegate定义

public delegate int myDelegate(int x,int y);

上面的代码定义了一个新委托,它可以封装任何返回为int,带有两个int类型参数的方法。任何一个方法无论是实例方法还是静态方法,只要他们的签名(参数类型在一个方法中的顺序)和定义的委托是一样的,都可以把他们封装到委托中去。

 

 

 

 

 

产生委托实例和产生类实例(对象)差不多,假如我们有如下的方法:

public int sub(int x,int y){
       return(x+y);
}

 

 

 

 

 

我们就可以使用如下的代码得到一个委托实例

myDelegate calculatin=new myDelegate(sub); // 呵呵,用方法名!!!

 

 

 

 

 

 

 接下来我们就可以直接使用calculation调用sub方法了:

calculation(10,3);
当然也可以新建 委托数组,如下就建立了一个委托数组Calculation[]

 

 

 

 

 接下来我们就可以直接使用calculation调用sub方法了:

calculation(10,3);
当然也可以新建 委托数组,如下就建立了一个委托数组Calculation[]

 

 

 

 

 

       private delegate int Calculation(int a, int b);

       private static Calculation[] myCalculation=new Calculation[2];
此时,可以用委托数组中的成员来封装待委托方法,实现新建委托实例.
:

myCalculation[0]=new Calculation(MathClass.max); // 方法名
myCalculation[1]=new Calculation(MathClass.min); //
方法名

 

 

 

 

 

这样,也就可以用新建的委托实例数组,来直接调用方法了.

事件

 

 

 

 

 

C#中,委托的最基本的一个用处就是用于事件处理。是对象发送的消息,以发信号通知操作的发生,通俗一点讲,事件就是程序中产生了一件需要处理的信号。

事件的定义用关键字event声明,不过声明事件之前必须存在一个多路广播委托(一个委托同时委托多个方法

 

 

 

 

 

public delegate void Calculate(int x,int y);//返回值为void的委托自动成为多路广播委托;
public event  Calculate OnCalculate;

可以看出,事件的声明仅仅是比委托实例的声明多了个关键字event,事实上事件可以看作是一个为事件处理过程定制的多路广播委托。因此,定义了事件后,我们就可以通过向事件中操作符+=添加方法实现事件的预定或者是通过操作符-=取消一个事件,这些都与委托实例的处理是相同的。

下面再单独谈谈 事件代理 的相关概念及其应用:

我们就一起来模仿一个Button类及Button值改变后引发事件并执行自定义的ButtonTextChangeEvent事件处理函数的过程,从而以事件数据得到该Button赋值过多少次。

 

 

 

 

 

Using System;
namespace MyServerControlTest {
   public delegate void ButtonTextChangeEventHander ( object sender , EventArgs e ); //事件委托的声明。
   public class Button {
   public event ButtonTextChangeEventHander TxtChange;//定义一个事件委托的引用,以备外部进行事件的绑定.
   private string _Text;
   public string Text {
            get { return _Text; }
       set {
                     _Text = value;
                     System.EventArgs e = new EventArgs(); //这里是事件的基类实例.
                     ChangeTxt(e); //调用事件处理函数.
                }
   }
   private void ChangeTxt(EventArgs e)  { //事件处理函数.
   if( TxtChange != null )
   TxtChange(this,e);//真正调用外部指派的处理函数.
   }
   }
}
为什么要这样定义委托声明
delegate ButtonTextChangeEventHander (Object sender , EventArgs e )
原因也很简单,为了符合.net framework CLS的约定
Sender
:引发事件的对象 e:事件所带的数据,而之所以用EventArgs e 是因为这里的事件是无数据的,如果自定义具有数据的事件的话,还是要从System.EventArgs基类中继承。

 

 

 

 

 

需要指出的是:
if( TxtChange != null )

   TxtChange(this,e);
如果不加 if( TxtChange != null )
那么当TxtChange并没有绑定事件处理函数时,它将会引发“未将对象引用到实例”的Exception

 

 

 

 

 

   /**//**//**//// summary
   /// 事件处理类
   /// /summary
   public class DelegateDemo {
   //定义一个实例
   private Button button;

 

 

 

 

 

   public DelegateDemo(){
   InitializeComponent();
   //构造函数调用时,就开始操作button进行赋值。
   SetValues();

 

 

 

 

 

}

   public void InitializeComponent(){
   button = new Button();
   //button对象的TxtChange事件引用,进行事件与处理函数的绑定
   //前面已经说过了,EventHandler是一个类,所以要new进行创建它的实例,其主要是把button_TxtChange事件处理函数的地址传至这个委托实例
   button.TxtChange += new ButtonTextChangeEventHander(button_TxtChange);
   }
   public void SetValues() {
   string[] values = {"AAA","BBB","CCC","DDD","EEE"};
             for( int i = 0; i 5; i++ ) {
            //进行赋值,从而引发事件而直接调用button_TxtChange事件处理函数。
             button.Text = values[i];
            }
   }
  private void button_TxtChange(object sender, System.EventArgs e) {
   Console.WriteLine( " Button实例新值。其值为:" + ((Button)sender).Text );
   }
}
   public class MyMain  {
            public static void Main() {
             DelegateDemo delegateDemo = new DelegateDemo();
             Console.Read();
        }
   }
}

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

感觉还是讲的不是很清楚。再来看一个:

 

 

 

 

 

public class MyObject
{
   
public delegate void ClickHandler(object sender, EventArgs e);
   
public event ClickHandler Click;
   
protected void OnClick()
   {
      
if (Click != null)
         Click(
thisnull);
   }
}

 

 

 

 

 

 

 

 

 

 

 

ClickHandler 代理使用事件代理的标准模式来定义事件的签名。其名称的末尾是处理程序,它带有两个参数。第一个参数是发送对象的对象,第二个参数用于传递事件的伴随信息。这种情况下没有要传递的信息,因此直接使用 EventArgs,但是如果有数据要传递,则使用从 EventArgs 派生的类(例如 MouseEventArgs)。

“Click”事件的声明执行两项操作:首先,它声明一个名为“Click”的代理成员变量,该变量从类的内部进行使用。其次,它声明一个名为“Click”的事件,该事件可按照常规访问规则从类的外部进行使用。

 

 

 

 

 

通常,将包括 OnClick() 等函数,以便使类型或派生类型能够触发事件。由于“Click”是代理,您将会注意到,用来触发事件的代码与代理的代码相同。

与代理类似,我们使用 += 和 -= 来挂接到事件或解除事件挂接,但与代理不同的是,仅可对事件执行这些操作。这可确保不会发生先前所讨论的两种错误。

使用事件是一种直截了当的方法。

 

class Test
{
   
static void ClickFunction(object sender, EventArgs args)
   {
      
// process the event here.
   }
   
public static void Main()
   {
      MyObject myObject 
= new MyObject();

      myObject.Click 
+= new MyObject.ClickHandler(ClickFunction);      
   }
}

 

我们创建一个与代理签名相匹配的静态函数或成员函数,然后用 += 向事件中添加代理的一个新实例

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 接下来我们就可以直接使用calculation调用sub方法了:

calculation(10,3);
当然也可以新建 委托数组,如下就建立了一个委托数组Calculation[]

 

 

 

 

 

 

 

 

 

 

 

原创粉丝点击