【美高梅开户网址】寄托和事件,事件的解密

委托

原为出处:

 事件概述                                                           

在前边壹篇中写到了委托,也说了委托是C#中诸多特征的基本功,这篇要讲的风云,便是创设在信托之上的。在C#一.0中,委托和事件是最根本的多少个特色。

寄托与事件,常常拿来就用,往往忘记其完毕原理,对其行使办法也进一步局限。周家安先生在《C#
陆.0
学习笔记》中对信托和事件的讲解,深远浅出,清晰明了,故专程摘抄1篇小说,勤看勤思。

在.NET在,我们平日利用委托,委托的功力不必多说,在.NET
二.0事先,我们在使用委托从前,得自定义1个信托项目,再利用那些自定义的嘱托类型定义贰个寄托字段或变量。.NET
贰.0给我们带来了Action、Func七个泛型委托,.NET3.0给大家带来了Lambda,那全体使得委托的概念和行使变得不难起来。上边包车型大巴事例中的委托都使用了拉姆da表明式。

   
 在爆发别的类或对象关怀的政工作时间,类或对象可经过事件通报它们。发送(或吸引)事件的类称为“发行者”,接收(或处理)事件的类称为“订户”。

一、什么是事件?

首先,委托是一种样式上与措施签名相似的类型。

1.Action文山会海的泛型委托

  • 特点
    • 发行者明显几时引发风浪,订户明显实施何种操作来响应该事件。
    • 一个事件能够有三个订户。三个订户可处理来自三个发行者的三个事件。
    • 尚无订户的事件永远不会被调用。
    • 事件无独有偶用于布告用户操作
    • 设若2个风浪有几个订户,当引发该事件时,会壹起调用多少个事件处理程序,也得以安装异步调用事件。
    • 【美高梅开户网址】寄托和事件,事件的解密。能够选取事件联合线程。
    • 事件是依照 伊芙ntHandler 委托和
      伊芙ntArgs 基类的。

事件设计到两类剧中人物——事件公布者和事件订阅者。当有个别事件时有产生后,事件宣布者会发布音讯;事件订阅者会吸收到新闻,并做出相应的拍卖,那就是事件的进度。

概念2个信托:

Action连串的寄托定义的是从未重返值(重回值为void)的委托。它有三个本子包涵没有输入参数,三个输入参数,二个输入参数,三个输入参数,陆个输入参数共5个本子那多少个本子的原型如下:

 事件的订阅和收回订阅                                       

 

public delegate void DoSome(string msg);

1.       未有输入参数重回值为void的委托.

     假使你想编写引发轩然大波时调用的自定义代码,则足以订阅由别的类公布的风云。例如,可以订阅某些按钮的“单击”事件,以使应用程序在用户单击该按钮时实施一些卓有成效的操作。

二、使用事件

 

Action委托 封装2个方式,该格局不采用参数并且不再次来到值。

  • 订阅事件
    • VS IDE 订阅事件
      • 设若“属性”窗口不可知,请在“设计”视图中,右击要创建事件处理程序的窗体或控件,然后选择“属性”。
      • 在“属性”窗口的顶部,单击“事件”图标。
      • 双击要开创的风浪,Visual C#
        会创立三个空事件处理程序方法,并将其添加到您的代码中。恐怕,您也足以在“代码”视图中手动添加代码。
    • 编制程序格局订阅事件

      • 概念一个事件处理程序方法,其签名与该事件的寄托签名匹配。例如,假诺事件基于
        伊夫ntHandler 委托类型,则上边包车型的士代码表示方法存根

二.壹 定义事件

应用首要字 delegate, 类型名字为 DoSome(string msg).

能够动用此委托以参数格局传递一个实施某操作的措施,而不用显式声飞鹤个自定义的委托来封装此方法。该包裹的艺术必须与此委托定义的不2秘籍签名相对应。那意味着该措施不得持有参数和再次来到值。例:

void HandleCustomEvent(object sender, CustomEventArgs a){  }

在C#中定义事件和定义类的成员是很相像的,只要3个event关键字就足以了。比如:

 

using System;

      • 选择加法赋值运算符 (+=)
        来为事件附加事件处理程序。在底下的以身作则中,假若名称为 publisher
        的指标具备1个名叫 RaiseCustom伊芙nt
        的轩然大波。请留心,订户类须要引用发行者类才能订阅其事件。

public event EventHandler birthday;

 

using System.Windows.Forms;

publisher.RaiseCustomEvent += HandleCustomEvent;
publisher.RaiseCustomEvent += new CustomEventHandler(HandleCustomEvent);

当中event是重要字,而伊芙ntHandler是信托项目。

创立三个DoSome(string
msg)委托项目对象,并实例化。

public class Name

    • 匿名方式订阅事件
      • 运用加法赋值运算符 (+=)
        来为事件附加匿超级模特式。在底下的以身作则中,假诺名字为 publisher
        的对象拥有一个名叫 RaiseCustom伊夫nt 的风浪,并且还定义了三个Custom伊芙ntArgs
        类以承载有些种类的专用事件消息。请留心,订户类须求引用
        publisher 才能订阅其事件。

由此能够把事件定义的协会总括为:访问修饰符 event 委托项目
事件名;在那之中央委员托项目能够是自定义的委托项目,也得以是.NET类库中预订义的嘱托项目伊夫ntHandler。

 1 static void TestDo(string str)
 2 {
 3      // ToDo
 4 }
 5 
 6 
 7 DoSome d1 = new DoSome(TestDo);
 8 
 9 
10 // 或者
11 
12 DoSome  d2;
13 
14 d2 = TestDo;

{

publisher.RaiseCustomEvent += delegate(object o, CustomEventArgs e)
{
    string s = o.ToString() + " " + e.ToString();
    Console.WriteLine(s);
};

二.二 订阅和裁撤事件

 委托列表

   private string instanceName;

  • 打消订阅

事件订阅者供给订阅事件公布者发表的风浪消息,以便在事件被触发式接收音讯并做出相应处理。在C#中,能够行使“+=”来订阅事件,使用“-=”来打消订阅事件。

 1 public delegate void DoSome(string msg);
 2 static void Main(string[] args)
 3 {
 4     DoSome d = new DoSome(TestDo);
 5     d("Hello");
 6     Console.WriteLine("--------------------------------------");
 7     d += new DoSome(Test1);
 8     d("123");
 9     Console.WriteLine("--------------------------------------");
10     d += TDo2;
11     d("world");
12     Console.WriteLine("--------------------------------------");
13     d -= TestDo;
14     d("nihao");
15 }
16 
17 static void TestDo(string str)
18 {
19     Console.WriteLine(str);
20 }
21 
22 static void Test1(string str)
23 {
24     Console.WriteLine("Test1 + " + str);
25 }
26 static void TDo2(string str)
27 {
28     Console.WriteLine("TDo2 + " + str);
29 }

   public Action ShowName;

   
 要提防在吸引事件时调用事件处理程序,您只需撤除订阅该事件。要桑土绸缪能源败露,请在自由订户对象在此以前裁撤订阅事件,那一点很首要。在撤除订阅事件在此之前,在颁发对象中作为该事件的底子的多路广播委托会引用封装了订户的事件处理程序的信托。只要宣布对象涵盖该引用,就不会对订户对象实施垃圾回收。

public class Bridegroom
{
  //自定义委托
  public delegate void MarryHandler(string msg);
  //使用自定义委托类型定义事件,事件名称为Marry伊夫nt
  public event MarryHandler MarryEvent;

输出:

   public Show()

     使用减法赋值运算符 (-=)
废除订阅事件。全数订户都收回订阅某事件后,发行者类中的事件实例会设置为
null。

  //发出事件
  public void OnMarriageComing(string msg)
  {
    //判断是或不是绑定了事件处理方法
    if(MarryEvent!=null)
    {
      //触发事件
      MarryEvent(msg);
    }
  }

美高梅开户网址 1

{

publisher.RaiseCustomEvent -= HandleCustomEvent;

  static void Main(string[] msg)
  {
    Bridegroom bridegroom=new Bridegroom();

 

   If(ShowName != null)

 宣布标准事件                                           

    //实例化朋友对象
    Friend friend1=new Friend(“张三”);
    Friend friend2=new Friend(“李四”);
    Friend friend3=new Friend(“王五”);

事件

    ShowName();

     上边包车型地铁进度演示了怎样将符合标准 .NET
Framework 方式的风浪添加到您本人的类和布局中。.NET Framework
类库中的全数事件均依照 伊芙ntHandler 委托,定义如下。

    //使用“+=”来订阅事件
    bridegroom.MarryEvent+=new MarryHandler(friend1.SendMessage);
    bridgeroom.MarryEvent+=new MarryHandler(friend2.SendMessage);

 事件自己便是寄托项目。

}

public delegate void EventHandler(object sender, EventArgs e);

    //发出布告,此时只有订阅了轩然大波的靶子才能接纳文告
    bridegroom.OnMarriageComing(“Friend,I Will Marry!!”);
    Console.WriteLine(“————————————“);

 1     class MyApp
 2     {
 3         public delegate void SpaceKeyPressedEventHandler();
 4 
 5         // 声明事件
 6         public event SpaceKeyPressedEventHandler SpaceKeyPressed;
 7 
 8         // 通过该方法引发事件
 9         protected virtual void OnSpaceKeyPressed()
10         {
11 
12             if (this.SpaceKeyPressed != null)
13             {
14                 // 将事件分发
15                 SpaceKeyPressed();
16             }
17         }
18 
19         // 启动事件监听的接口
20         public void StartRun()
21         {
22             // 监听事件
23             while (true)
24             {
25                 ConsoleKeyInfo keyinfo = Console.ReadKey();
26                 if (keyinfo.Key == ConsoleKey.Spacebar)
27                 {
28                     // 引发事件
29                     OnSpaceKeyPressed();
30                 }
31 
32                 if (keyinfo.Key == ConsoleKey.Escape)
33                 {
34                     // 跳出循环
35                     break;
36                 }
37             }
38         }
39     }
40 
41     class Program
42     {
43        
44         static void Main(string[] args)
45         {
46             MyApp app = new MyApp();
47             // 订阅事件,指定处理事件的方法
48             app.SpaceKeyPressed += app_SpaceKeyPressed;
49             app.SpaceKeyPressed += app_SecondEventHandler;
50 
51             // 启动事件监听
52             app.StartRun();
53         
54         }   
55 
56         // 事件处理1
57         private static void app_SpaceKeyPressed()
58         {
59             Console.WriteLine("{0} 按下空格键。", DateTime.Now.ToLongTimeString());
60         }
61         // 事件处理2
62         private static void app_SecondEventHandler()
63         {
64             Console.WriteLine("事件的第二个处理方法。");
65         }
66 
67     }

   public Name(string name)

  • 选择 EventHandler
    情势宣布事件
    • (假使不供给发送含事件的自定义数据,请跳过此步骤,直接进去步骤
      3。)在发行者类和订户类均可尽收眼底的限量中申明类,并丰盛保留自定义事件数量所需的分子。在此示例中,会回到二个简练字符串。

    //使用”-=”来裁撤事件订阅,此时李四将收不到通告
    bridegroom.MarryEvent-=new MarryHandler(friend2.SendMessage);

平日,作为事件委托,有七个参数,七个是Object类型,表示引发风浪的目的,便是什么人引发了轩然大波的,多数景色下在调用事件时是把类的当下实例引用(this)传递过去。另1个参数是从System.EventArgs派省的类的实例。那是3个正规的事件处理程序的签署,为了规范事件的拍卖,.NET类库已经定义好3个System.伊芙ntHandler委托,用于证明事件。它的原型如下:

   {

public class CustomEventArgs : EventArgs
{
    public CustomEventArgs(string s)
    {
        msg = s;
    }
    private string msg;
    public string Message
    {
        get { return msg; }
    } 
}

    bridegroom.MarryEvent+=new MarryHandler(friend3.SendMessage);

1 public delegate void EventHandler(object sender, EventArgs e);

      this.instanceName = name;

    • (假诺你使用的是 伊夫ntHandler
      的泛型版本,请跳过此步骤。)在公布类中宣称一个寄托。为它钦赐以
      伊夫ntHandler 结尾的名号。第二个参数钦赐自定义 伊夫ntArgs
      类型。

    bridegroom.OnMarriageComing(“Friend,I Will Marry!!”);

 引发风浪的靶子实例将传递给sender参数,而与事件有关的数码则传递给e参数。固然不必要传递过多的数额,能够通过System.伊芙ntArgs.Empty静态成员再次回到3个空的伊芙ntArgs对象类传递。

   }

public delegate void CustomEventHandler(object sender, CustomEventArgs a);

    Console.ReadKey();
  }
}

可是,由于分歧的事件要传递的参数分化,更加多时候是从伊夫ntArgs类派生的子类的实例,显明二个伊夫ntHandler委托是无法满意各类情况的。要是针对差异的事件也顶二个1个相应的委托,水量一旦多起来,既混乱,也倒霉管理。为了缓解这一个题材,.NET类库又提供了贰个富含泛型参数的事件处理委托。原型如下:

   public void DisplayToConsole()

    • 动用以下任一步骤,在揭橥类中注明事件。
      • 倘使未有自定义 伊芙ntArgs
        类,事件类型就是非泛型 伊芙ntHandler
        委托。它无需注脚,因为它已在 C# 项目暗中同意包涵的 System
        命名空间中开始展览了申明

  public class Friend
  {
    public string Name;
    public Friend(string name)
    {
      Name=name;
    }
    //事件处理函数,该函数需求符合MarryHandler委托的定义
    public void SendMessage(string message)
    {
      Console.WriteLine(message);
      Console.WriteLine(this.Name+”收到了,到时候准时参加”);
    }
  }

1 public delegate void EventHandler<TEventArgs>(object sender, TEventArgs e);

   {

public event EventHandler RaiseCustomEvent;

值得注意的是,事件处理函数的定义要求与自定义的委托定义保持壹致,即参数个数,参数类型和重返类型等必要与信托同壹。

T伊芙ntArgs
是1个泛型参数,应该是System.伊夫ntArgs类大概System.伊芙ntArgs类的派生类型。

      Console.WriteLine(this.instanceName);

      • 假如应用的是 伊芙ntHandler
        的非泛型版本,并且您有三个由 伊芙ntArgs
        派生的自定义类,请在发布类中宣示您的事件,并且将您的委托用作类型

而外利用自定义委托项目来定义事件外,还是能够使用.NET类库中预约义的委托项目伊芙ntHandler来定义事件,供给留意它们的参数。

泛型参数的事件,实例:

   }

class Publisher
{
    public event CustomEventHandler RaiseCustomEvent;
}

public class Bridegroom
{
  //使用.NET类库中的类型定义事件,事件名字为Marry伊芙nt
  public event EventHandler
MarryEvent;

 1     // EventArgs 派生类
 2     // 创建泛型参数  KeyPressedEventArgs 类
 3     public class KeyPressedEventArgs : EventArgs
 4     {
 5         public ConsoleKey pressedKey { get; private set; }
 6         public KeyPressedEventArgs(ConsoleKey key)
 7         {
 8             pressedKey = key;
 9         }
10     }
11 
12     public class MyApp
13     {
14         // 捕捉按键的事件 声明一个泛型参数KeyPressedEventArgs类型的
15         public event EventHandler<KeyPressedEventArgs> KeyPressed;
16 
17         // 通过该方法引发事件
18         protected virtual void OnKeyPressed(KeyPressedEventArgs e)
19         {
20             if (this.KeyPressed != null )
21             {
22                 this.KeyPressed(this, e);
23             }
24         }
25 
26         // 事件监听端口启动
27         public void Start()
28         {
29             while (true)
30             {
31                 ConsoleKeyInfo keyInfo = Console.ReadKey();
32                 // 如果按下了ESC键,则退出循环
33                 if (keyInfo.Key == ConsoleKey.Escape)
34                 {
35                     break;
36                 }
37                 // 引发事件
38                 OnKeyPressed(new KeyPressedEventArgs(keyInfo.Key));
39             }
40         }
41     }
42 
43 
44     class Program
45     {
46        
47         static void Main(string[] args)
48         {
49             
50             MyApp app = new MyApp();
51             // 订阅事件,指定处理事件的方法
52             app.KeyPressed += app_KeyPressed;
53             // 启动事件监听
54             app.Start();
55         }   
56 
57         // 事件处理
58         private static void app_KeyPressed(Object sender, KeyPressedEventArgs e)
59         {
60             Console.WriteLine("已按下 {0} 键", e.pressedKey.ToString());
61         }
62         
63     }

   public void DisplayToWindow()

      • 假诺采纳的是泛型版本,则不必要自定义委托。相反,应将事件类型内定为
        伊芙ntHandler<Custom伊芙ntArgs>,在尖括号内停放您自个儿的类的名号。

  //发出事件
  public void OnMarriageComing(string msg)
  {
    //判断是不是绑定了事件处理方法
    if(MarryEvent!=null)
    {
      Console.WriteLine(msg);
      //触发事件
      MarryEvent(this,new EventArgs());
    }
  }

 

   {

public event EventHandler<CustomEventArgs> RaiseCustomEvent;

  static void Main(string[] msg)
  {
    Bridegroom bridegroom=new Bridegroom();

      MessageBox.Show(this.instanceName);

 吸引派生类中的基类事件                                      

    //实例化朋友对象
    Friend friend1=new Friend(“张三”);
    Friend friend2=new Friend(“李四”);
    Friend friend3=new Friend(“王五”);

   }

   
 以下简单示例演示了在基类中评释可从派生类引发的事件的标准方法。此方式广泛应用于
.NET Framework 基类库中的 Windows 窗体类。

    //使用“+=”来订阅事件
    bridegroom.MarryEvent+=new MarryHandler(friend1.SendMessage);
    bridgeroom.MarryEvent+=new MarryHandler(friend2.SendMessage);

}

     在成立可用作别的类的基类的类时,必须思量如下事实:事件是例外类别的委托,只好够从注解它们的类中调用。派生类不可能直接调用基类中扬言的轩然大波。固然有时你大概希望有个别事件只好通过基类引发,但在大部气象下,您应该允许派生类调用基类事件。为此,您能够在含蓄该事件的基类中开创一个受保证的调用方法。通过调用或重写此调用方法,派生类便得以直接调用该事件。

    //发出公告,此时只有订阅了风云的目的才能吸收接纳通知
    bridegroom.OnMarriageComing(“Friend,I Will Marry!!”);
    Console.WriteLine(“————————————“);

public class ActionStudy

namespace BaseClassEvents
{
    using System;
    using System.Collections.Generic;
    public class ShapeEventArgs : EventArgs
    {
        private double newArea;

        public ShapeEventArgs(double d)
        {
            newArea = d;
        }
        public double NewArea
        {
            get { return newArea; }
        }
    }
    public abstract class Shape
    {
        protected double area;

        public double Area
        {
            get { return area; }
            set { area = value; }
        }
        public event EventHandler<ShapeEventArgs> ShapeChanged;
        public abstract void Draw();
        protected virtual void OnShapeChanged(ShapeEventArgs e)
        {
            EventHandler<ShapeEventArgs> handler = ShapeChanged;
            if (handler != null)
            {
                handler(this, e);
            }
        }
    }
    public class Circle : Shape
    {
        private double radius;
        public Circle(double d)
        {
            radius = d;
            area = 3.14 * radius;
        }
        public void Update(double d)
        {
            radius = d;
            area = 3.14 * radius;
            OnShapeChanged(new ShapeEventArgs(area));
        }
        protected override void OnShapeChanged(ShapeEventArgs e)
        {
            base.OnShapeChanged(e);
        }
        public override void Draw()
        {
            Console.WriteLine("Drawing a circle");
        }
    }
    public class Rectangle : Shape
    {
        private double length;
        private double width;
        public Rectangle(double length, double width)
        {
            this.length = length;
            this.width = width;
            area = length * width;
        }
        public void Update(double length, double width)
        {
            this.length = length;
            this.width = width;
            area = length * width;
            OnShapeChanged(new ShapeEventArgs(area));
        }
        protected override void OnShapeChanged(ShapeEventArgs e)
        {
            base.OnShapeChanged(e);
        }
        public override void Draw()
        {
            Console.WriteLine("Drawing a rectangle");
        }

    }
    public class ShapeContainer
    {
        List<Shape> _list;

        public ShapeContainer()
        {
            _list = new List<Shape>();
        }

        public void AddShape(Shape s)
        {
            _list.Add(s);
            s.ShapeChanged += HandleShapeChanged;
        }
        private void HandleShapeChanged(object sender, ShapeEventArgs e)
        {
            Shape s = (Shape)sender;
            Console.WriteLine("Received event. Shape area is now {0}", e.NewArea);
            s.Draw();
        }
    }
    class Test
    {

        static void Main(string[] args)
        {
            Circle c1 = new Circle(54);
            Rectangle r1 = new Rectangle(12, 9);
            ShapeContainer sc = new ShapeContainer();
            sc.AddShape(c1);
            sc.AddShape(r1);
            c1.Update(57);
            r1.Update(7, 7);
            Console.WriteLine();
            Console.WriteLine("Press Enter to exit");
            Console.ReadLine();
        }
    }
}

    //使用”-=”来撤废事件订阅,此时李4将收不到布告
    bridegroom.MarryEvent-=new MarryHandler(friend2.SendMessage);

{

 兑现接口事件                                            

    bridegroom.MarryEvent+=new MarryHandler(friend3.SendMessage);

   public static void Main()

   
 接口可证明事件。上边包车型客车示范演示怎么着在类中贯彻接口事件。接口事件的兑现规则与此外接口方法或性质的贯彻规则基本相同。

    bridegroom.OnMarriageComing(“Friend,I Will Marry!!”);

   {

  • 在类中落到实处接口事件

    Console.ReadKey();
  }
}

      Name testName = new Name(“Koani”);

   
 在类中扬言事件,然后在适合的职位调用该事件。

public class Friend
{
  public string Name;
  public Friend(string name)
  {
    Name=name;
  }
  //事件处理函数,该函数需求符合MarryHandler委托的概念
  public void SendMessage(object
s,EventArgs e
)
  {
    Console.WriteLine(this.Name+”收到了,到时候准时参加”);
  }
}

      testName.ShowName  = () => testName.DisplayToWindow();

public interface IDrawingObject
{
    event EventHandler ShapeChanged;
}
public class MyEventArgs : EventArgs {…}
public class Shape : IDrawingObject
{
    event EventHandler ShapeChanged;
    void ChangeShape()
    {
        // Do something before the event…
        OnShapeChanged(new MyEventsArgs(…));
        // or do something after the event. 
    }
    protected virtual void OnShapeChanged(MyEventArgs e)
    {
        if(ShapeChanged != null)
        {
           ShapeChanged(this, e);
        }
    }
}

伊芙ntHandler是.NET类库中预约义的嘱托项目,用于拍卖不含有事件数量的事件。使用Reflector来查阅伊芙ntHandler的现实定义:

      testName.Show();

     下边包车型地铁以身作则演示怎么着处理以下的不常见事态:您的类是从两个以上的接口继承的,每一个接口都富含同名事件)。在那种情景下,您至少要为在那之中一个事件提供显式接口完成。为事件编写显式接口实现时,必须编制add 和 remove
事件访问器。那八个事件访问器平时由编写翻译器提供,但在那种景色下编写翻译器无法提供。

[Serializable, ComVisible(true), __DynamicallyInvokable]
public delegate void EventHandler(object sender, EventArgs e);

   }

美高梅开户网址,     您能够提供温馨的访问器,以便钦点那多个事件是由你的类中的同一事件表示,依然由区别事件代表。例如,依照接口规范,假使事件应在差别时间引发,则足以将每种事件与类中的五个独自达成关系。在上边的示范中,订户将造型引用强制转换为
IShape 或 IDrawingObject,从而分明自个儿将会收下哪个 OnDraw 事件。

从概念中得以看来,该委托类型的回到类型为void,第一个参数sender负责保存触发事件目的的引用,其品种为object;第二个参数e负责保存事件数量。伊芙ntArgs类也是.NET类库中定义的类,它不保留任何数据,假诺想在事变中带有事件数量,就亟须选取伊芙ntArgs的派生类来达成。

}

namespace WrapTwoInterfaceEvents
{
    using System;
    public interface IDrawingObject
    {
        event EventHandler OnDraw;
    }
    public interface IShape
    {
        event EventHandler OnDraw;
    }
    public class Shape : IDrawingObject, IShape
    {
        event EventHandler PreDrawEvent;
        event EventHandler PostDrawEvent;
        event EventHandler IDrawingObject.OnDraw
        {
            add { PreDrawEvent += value; }
            remove { PreDrawEvent -= value; }
        }
        event EventHandler IShape.OnDraw
        {
            add { PostDrawEvent += value; }
            remove { PostDrawEvent -= value; }
        }
        public void Draw()
        {
            EventHandler handler = PreDrawEvent;
            if (handler != null)
            {
                handler(this, new EventArgs());
            }
            Console.WriteLine("Drawing a shape.");
            handler = PostDrawEvent;
            if (handler != null)
            {
                handler(this, new EventArgs());
            }
        }
    }
    public class Subscriber1
    {
        public Subscriber1(Shape shape)
        {
            IDrawingObject d = (IDrawingObject)shape;
            d.OnDraw += new EventHandler(d_OnDraw);
        }
        void d_OnDraw(object sender, EventArgs e)
        {
            Console.WriteLine("Sub1 receives the IDrawingObject event.");
        }
    }
    public class Subscriber2
    {
        public Subscriber2(Shape shape)
        {
            IShape d = (IShape)shape;
            d.OnDraw += new EventHandler(d_OnDraw);
        }

        void d_OnDraw(object sender, EventArgs e)
        {
            Console.WriteLine("Sub2 receives the IShape event.");
        }
    }
    public class Program
    {
        static void Main(string[] args)
        {
            Shape shape = new Shape();
            Subscriber1 sub = new Subscriber1(shape);
            Subscriber2 sub2 = new Subscriber2(shape);
            shape.Draw();

            Console.WriteLine("Press Enter to close this window.");
            Console.ReadLine();
        }
    }
}

2.3 扩展EventArgs类

二.       有1个输入参数重返值为void的信托

 应用字典存款和储蓄事件实例                                       

地方说了,假如要在事变中隐含事件数量,就务须利用伊芙ntArgs的派生类。具体的落到实处代码如下:

Action<T>泛型委托封装1个主意,该措施只使用二个参数并且不重返值。

     accessor-declarations
的一种用法是当着大气的轩然大波但不为每个事件分配字段,而是利用字典来储存那一个事件实例。那唯有在全部更多的风浪、但您预计大多数轩然大波都不会促成时才有用。

public class
MarryEventArgs:EventArgs

{
  public string Message;
  public MarryEventArgs(string msg)
  {
    Message=msg;
  }
}

能够采用此委托以参数形式传递格局,而不用显式评释自定义的嘱托。该办法必须与此

public delegate void EventHandler1(int i);
public delegate void EventHandler2(string s);
public class PropertyEventsSample
{
    private System.Collections.Generic.Dictionary<string, System.Delegate> eventTable;
    public PropertyEventsSample()
    {
        eventTable = new System.Collections.Generic.Dictionary<string, System.Delegate>();
        eventTable.Add("Event1", null);
        eventTable.Add("Event2", null);
    }
    public event EventHandler1 Event1
    {
        add
        {
            eventTable["Event1"] = (EventHandler1)eventTable["Event1"] + value;
        }
        remove
        {
            eventTable["Event1"] = (EventHandler1)eventTable["Event1"] - value;
        }
    }
    public event EventHandler2 Event2
    {
        add
        {
            eventTable["Event2"] = (EventHandler2)eventTable["Event2"] + value;
        }
        remove
        {
            eventTable["Event2"] = (EventHandler2)eventTable["Event2"] - value;
        }
    }
    internal void RaiseEvent1(int i)
    {
        EventHandler1 handler1;
        if (null != (handler1 = (EventHandler1)eventTable["Event1"]))
        {
            handler1(i);
        }
    }
    internal void RaiseEvent2(string s)
    {
        EventHandler2 handler2;
        if (null != (handler2 = (EventHandler2)eventTable["Event2"]))
        {
            handler2(s);
        }
    }
}
public class TestClass
{
    public static void Delegate1Method(int i)
    {
        System.Console.WriteLine(i);
    }
    public static void Delegate2Method(string s)
    {
        System.Console.WriteLine(s);
    }
    static void Main()
    {
        PropertyEventsSample p = new PropertyEventsSample();

        p.Event1 += new EventHandler1(TestClass.Delegate1Method);
        p.Event1 += new EventHandler1(TestClass.Delegate1Method);
        p.Event1 -= new EventHandler1(TestClass.Delegate1Method);
        p.RaiseEvent1(2);

        p.Event2 += new EventHandler2(TestClass.Delegate2Method);
        p.Event2 += new EventHandler2(TestClass.Delegate2Method);
        p.Event2 -= new EventHandler2(TestClass.Delegate2Method);
        p.RaiseEvent2("TestString");
    }
}

public class Bridegroom
{
  //自定义委托项目,委托包蕴多个参数
  public delegate void MarryHandler(object sender,MarryEventArgs e);
  //使用自定义委托类型定义事件,事件名称叫Marry伊夫nt
  public event MarryHandler MarryEvent;
  //发出事件
  public void OnMarriageComing(string msg)
  {
    //判断是或不是绑定了事件处理方法
    if(MarryEvent!=null)
    {
      //触发事件
      MarryEvent(this,new
MarryEventArgs(msg));

    }
  }

信托定义的办法签名相呼应。也正是说,封装的办法必须持有三个经过值传递给它的参数,并且不可能再次回到值。例:

 事件的异步情势                            

  static void Main(string[] msg)
  {
    Bridegroom bridegroom=new Bridegroom();
    //实例化朋友对象
    Friend friend1=new Friend(“张三”);
    Friend friend2=new Friend(“李四”);
    Friend friend3=new Friend(“王五”);
    //使用“+=”来订阅事件
    bridegroom.MarryEvent+=new MarryHandler(friend1.SendMessage);
    bridgeroom.MarryEvent+=new MarryHandler(friend2.SendMessage);
    //发出通知,此时唯有订阅了轩然大波的靶子才能接到通知
    bridegroom.OnMarriageComing(“Friend,I Will Marry!!”);
    Console.WriteLine(“————————————“);
    //使用”-=”来撤消事件订阅,此时李肆将收不到布告
    bridegroom.MarryEvent-=new MarryHandler(friend2.SendMessage);
    bridegroom.MarryEvent+=new MarryHandler(friend3.SendMessage);
    bridegroom.OnMarriageComing(“Friend,I Will Marry!!”);
    Console.ReadKey();
  }
}

using System;

     有多样格局可向客户端代码公开异步作用。基于事件的异步情势为类规定了用来显示异步行为的提出措施。对于相对不难的四线程应用程序,BackgroundWorker
组件提供了1个粗略的消除方案。对于更复杂的异步应用程序,请想念达成3个顺应基于事件的异步方式的类。

public class Friend
{
  public string Name;
  public Friend(string name)
  {
    Name=name;
  }
  //事件处理函数,该函数必要符合MarryHandler委托的定义
  public void SendMessage(object
s,MarryEventArgs e
)
  {
    Console.WriteLine(e.Message);
    Console.WriteLine(this.Name+”收到了,到时候准时插手”);
  }
}

using System.Windows.Forms;

    • “在后台”执行耗费时间职务(例如下载和数据库操作),但不会暂停您的应用程序。
    • 而且履行四个操作,各类操作达成时都会吸收接纳通报。
    • 等候能源变得可用,但不会停下(“挂起”)您的应用程序。
    • 应用深谙的事件和嘱托模型与挂起的异步操作通讯。

经过自定义Marry伊夫ntArgs事件类扩充了伊芙ntArgs类,此时Marry伊夫ntArgs带有一个名叫Message的轩然大波参数;然后在订阅对象的SendMessage方法中,通过e.Message的办法获得了风浪数量,并把事件数量输出。

public class ActionStudy

 

{

三、事件的大茂山真面目

   public static void Main()

从以上的例证我们得以知晓,事件是在信托的基础之上的。那么,它们终归具备什么的关联呢,这些就必须透过Reflector来窥探了。

   {

一句话来说的源代码:

      Action<string> messageTarget;

namespace 窥探事件真相
{
  class Program
  {
    public delegate void MarryHanler(string msg);

      if (Environment.GetCommandLineArgs().Length > 1)

    public event MarryHanler MarryEvent;
    static void Main(string[] args)
    {
    }
  }
}

         messageTarget = s => MessageBox.Show(s);

Reflector反编写翻译的结果:

      else

美高梅开户网址 2

         messageTarget = s => Console.WriteLine(s);

图1

      messageTarget(“Hello, World!”);

 

   }

美高梅开户网址 3

}

图2

上边包车型客车以身作则演示怎么样采纳 Action(T) 委托来打字与印刷 List(T) 对象的始末。在此示例中,使用 Print 方法将列表的内容展现到控制台上。别的,C# 示例还以身作则怎么样运用匿名格局将内容展现到控制台上。

 

using System;

美高梅开户网址 4

using System.Collections.Generic;

图3

class Program

美高梅开户网址 5

{

图4

    static void Main()

能够观察,C#事件被编写翻译成包括多个国有措施的代码段,三个包涵add_前缀,另二个分包remove_前缀,前缀前面是C#事件的称谓。

    {

在add_主意中,通过调用了Delegate.Combine()方法来贯彻的(图3中红框的地点),Delegate.Combine()方法将七个委托组合为了1个多路广播委托。

        Action<string> PrintInConsole = s =>
Console.WriteLine(s);

在remove_主意中,同样利用了Delegate.Remove()方法。

        Action<string> PrintInDialog = s=>MessageBox.Show(s);

由地点的4张图中得以总括出:

        List<String> names = new List<String>();

C#的事件是八个不相同常常的多路广播委托,事件暗许含有贰个私人住房的信托项目变量(图二的红框),该变量用于保存对事件处理方法的引用,且该信托项目标变量为民用,只好从概念该事件的类中展开访问。

        names.Add(“Bruce”);

从反编写翻译的代码中能够看看跟大家学过的性能是形似的。但与事件分歧,属性中定义了set访问和get访问器,七个访问器的精神就是以”get_”和”set_”为前缀的三个点子。属性用于对类中的私有字段实行走访,而C#事件也得以当做是“委托字段的质量”,由此得以经过事件来对私有的信托字段进行访问,那也是C#事件性子存在的原委。C#事件机制符合面向对象的封装脾气,是代码更安全。

        names.Add(“Alfred”);

        names.Add(“Tim”);

        names.Add(“Richard”);

        names.ForEach(PrintInConsole);

        names.ForEach(PrintInDialog);      

    }

}

三.       有一个输入参数重返值为void的寄托

Action<T1,T二> 封装四个方法,该措施具有几个参数并且不重临值。

能够应用 Action(T1,
T2
) 委托以参数方式传递方式,而不用显式评释自定义的委托。该

措施必须与此委托定义的方法签名相对应。也就是说,封装的法子必须有所七个均通过值传递给它的参数,并且不可能重返值。

using System;

using System.IO;

public class ActinStudy

{

   public static void Main()

   {

      string message1 = “The first line of a message.”;

      string message2 = “The second line of a message.”;

      Action<string, string>  concat;

      if (Environment.GetCommandLineArgs().Length > 1)

         concat = (s1, s2) =>

{

StreamWriter writer = null; 

      try

      {

         writer = new
StreamWriter(Environment.GetCommandLineArgs()[1], false);

         writer.WriteLine(“{0}”n{1}”, s1, s2);

      }

      catch

      {

         Console.WriteLine(“File write operation failed…”);

      }

      finally

      {

         if (writer != null) writer.Close();

      }

};

      else

         concat = (s1, s2) => Console.WriteLine(“{0}”n{1}”, s1, s2);

      concat(message1, message2);

   }

四.       有三个输入参数重回值为void的信托

Action<T一,T2,T三>委托,封装三个办法,该措施应用三个参数并且不再次来到值。

能够运用 Action(T1, T2,
T3
) 委托以参数方式传递模式,而不用显式注脚自定义的委托。

该格局必须与此委托定义的艺术签名相呼应。也正是说,封装的不二等秘书籍必须具有多少个均经过值传递给它的参数,并且不能够再次回到值。

伍.       有6个输入参数再次来到值为void的嘱托

Action<T一,T2,T三,T四>委托, 封装三个措施,该办法具有三个参数并且不重回值。

能够使用 Action(T1, T2, T3,
T4
) 委托以参数情势传递格局,而不用显式申明自定义的委托。封装的主意必须与此委托定义的主意签名相呼应。约等于说,封装的诀窍必须具有三个均经过值传递给它的参数,并且不可能重回值。

2.Func系统的泛型委托

Func连串的信托定义的是再次来到值的信托。它有多少个本子包蕴未有输入参数,三个输入参数,3个输入参数,2个输入参数,5个输入参数共多个本子那多少个版本的原型如下:

1.       没有输入参数有重回值(重临值不为void)的嘱托

Func<TResult>封装二个不拥有参数但却回到 TResult 参数钦点的类型值的办法。
能够运用此委托构造3个能以参数形式传递的章程,而不用显式表明自定义的信托。该

措施必须与此委托定义的方法签名相呼应。那代表封装的法子不得持有参数,但无法不重返值。

2.       具有二个输入参数有再次回到值(重返值不为void)的寄托

  
Func<T,TResult>封装贰个具有1个参数并再次来到 TResult 参数钦点的类型值的不二秘诀。

能够采用此委托构造二个能以参数情势传递的点子,而不用显式表明自定义的嘱托。该办法必须与此委托定义的秘诀签名相呼应。也正是说,封装的章程必须持有贰个因而值传递给它的参数,并且必须重回值。

叁.       具有贰个输入参数有重返值(重临值不为void)的委托

  Func<T一,T2,TResult>封装二个享有2个参数并重返 TResult 参数钦定的类型值的主意。

能够应用此委托构造三个能以参数方式传递的方式,而不用显式评释自定义的信托。该格局必须与此委托定义的方法签名相呼应。也正是说,封装的法子必须持有五个均经过值传递给它的参数,并且必须重回值

四.       具有八个输入参数有重返值(重回值不为void)的嘱托

  
Func<T一,T二,T三,TResut>封装三个负有多少个参数并回到 TResult 参数钦赐的类型值的方法。

可以利用此委托构造2个能以参数格局传递的法门,而不用显式注脚自定义的委托。该方法必须与此委托定义的措施签名相对应。也正是说,封装的艺术必须具备八个均经过值传递给它的参数,并且必须再次回到值。

伍.       具有多少个输入参数有重返值(返回值不为void)的寄托

 Func<T1,T二,T3,TResult>封装二个持有多个参数并回到 TResult 参数内定的类型值的措施。

能够运用此委托构造多个能以参数情势传递的法子,而不用显式注明自定义的信托。该措施必须与此委托定义的点子签名相对应。也正是说,封装的主意必须具备三个均通过值传递给它的参数,并且必须重返值。

三. EventHandler(TEventArgs) 泛型委托

EventHandler(TEventArgs) 是1种预订义委托,表示事件的事件处理程序方法,它与事件是不是变动事件数量毫无干系。要是事件不扭转事件数量,则用EventArgs 替代泛型类型参数;不然,提供自身的自定义事件数据类型并用该类型替代泛型类型参数。

利用 伊夫ntHandler<(Of
<(T伊夫ntArgs>)>) 的独到之处在于,假诺事件生成事件数量,则无需编写本身的自定义委托代码。其余,.NET
Framework 只需三个兑现就能帮忙 伊芙ntHandler<(Of
<(T伊夫ntArgs>)>),那与代表泛型类型参数的风云数据类型非亲非故。

若要将事件与处监护人件的情势关联,请向事件添加委托的实例。除非移除了该信托,不然每当爆发该事件时就调用事件处理程序。

我们领悟,.NET
Framework 中的事件模型基于已有事件委托,该信托将事件与事件处理程序连接。引发风浪要求四个成分:

一     引用向事件提供响应的情势的寄托。

贰封存事件数量的类。

上边是MSDN上的2个简约的例子:

下边的代码示例申明事件数量和采用该事件数量的 伊芙ntHandler<(Of
<(T伊夫ntArgs>)>) 泛型委托,并演示怎么样抓住该事件。

using System;

using System.Collections.Generic;

//首先定义事件处理参数:这一个参数派生于伊芙ntArgs

public class MyEventArgs : EventArgs

{

    private string msg;

    public MyEventArgs( string messageData ) { msg = messageData;}

    public string Message {

        get { return msg; }

        set { msg = value; }

    }

}

//下边定义事件处理类,注意那里运用了伊夫ntHandler<T>委托项目

public class HasEvent

{

// Declare an event of delegate type EventHandler of

// MyEventArgs.

    public event EventHandler<MyEventArgs> SampleEvent;

    public void DemoEvent(string val)

    {

        //复制到权且变量,以保障线程安全

        EventHandler<MyEventArgs> temp = SampleEvent;

        if (temp != null)

            temp(this, new MyEventArgs(val));

    }

}

设若在从前的老艺术则上边的类则应该写为:

//首先得定义贰个委托

public delegate void MyEventHandler(Object sender, MyEventArgs args);

public class HasEvent

{

// Declare an event of delegate type EventHandler of

// MyEventArgs.

    public event MyEventHandler  SampleEvent;

    public void DemoEvent(string val)

    {

        //复制到一时半刻变量,以管教线程安全

        MyEventHandler  temp = SampleEvent;

        if (temp != null)

            temp(this, new MyEventArgs(val));

    }

}

看得出使用那么些泛型委托精简了不少代码.

//-上边包车型客车类订阅了上面定义的事件

public class Sample

{

    public static void Main()

    {

        HasEvent he = new HasEvent();

        he.SampleEvent +=

new ventHandler<MyEventArgs>((object src,MyEventArgs mea)
=> MessageBox.Show(mea.Message));//那里运用了拉姆da表明式

        he.DemoEvent(“Hey there, Bruce!”);

        he.DemoEvent(“How are you today?”);

        he.DemoEvent(“I’m pretty good.”);

        he.DemoEvent(“Thanks for asking!”);

    }

}

四.params参数类型的嘱托

在上头介绍的Action和Func种类的委托中,不可以利用由params关键字修改的参数,作者当然想用params关键字来促成可变类型的参数,结果发现行不通,那时只可以用生成类型的委托,可是请留目的在于用匿名方式绑定具有params关键字修饰的参数的嘱托时,匿名方式的参数中却不能够有params关键字,在匿名方式中唯有去掉了params关键字,固然从匿名格局中去掉了params关键字,但那并不妨碍行使同壹的语法.

譬如申明了之类类型的嘱托

public void delegate DelegateWithParamskeyword(params object[] param);

只是你去不能够用上边包车型地铁法门去绑定叁个匿名格局:

DelegateWithParamskeyword dwp = delegate(params object[] param)

{
 foreach(object o in param)

 {

    Console.WriteLine(o.ToString());

 }

}

或者

DelegateWithParamskeyword dwpkw = (params object[] param) =>
{foreach(object o in param)MessageBox.Show(o.ToString());};

而相应去掉上面匿超格局中的params关键字.

DelegateWithParamskeyword dwp = delegate(object[] param)

{
 foreach(object o in param)

 {

    Console.WriteLine(o.ToString());

 }

}

或者

DelegateWithParamskeyword dwpkw = (object[] param) =>
{foreach(object o in param) MessageBox.Show(o.ToString());};

就好像上边说的那并不影响你使用相同的的语法来调用委托

如: dwp(1,2,”x”,”y”,”dog”,9.28);

dwpkw(“dog”,”xy”,10);

故而,能够将匿名情势绑定到一个接纳params注脚的寄托,那样一来,就足以在调用时传出你希望的私行数指标参数。

发表评论

电子邮件地址不会被公开。 必填项已用*标注

网站地图xml地图