C#事件EVENT处理

首先了解一下事件程序流程

  • 定义事件参数类
  • 定义委托类型
  • 声明事件(发布事件者)
  • 定义事件的订阅者类
  • 定义 响应 事件的函数。 On开头的函数。(发布者中实现)
  • 定义 调用 事件函数的 业务逻辑。 (发布者中实现)

定义事件参数类

这个类中,我们只定义了动物的叫声。

/// <summary>
/// 事件
/// </summary>
public class AnimalEventArgs : EventArgs
{
	/// <summary>
	/// 叫声
	/// </summary>
	public string wow;
	/// <summary>
	/// 构造方法
	/// </summary>
	/// <param name="s">叫声</param>
	public AnimalEventArgs(string s)
	{
		this.wow = s;
	}
}

定义委托类型

/// <summary>
/// 事件的订阅者、事件的发布者
/// </summary>
class Animals
{
    /// <summary>
    /// 定义委托类型
    /// </summary>
    /// <param name="sender">事件的发布者</param>
    /// <param name="e">事件参数类</param>
    public delegate void WowEventHandler(object sender, AnimalEventArgs e); 
}

声明事件

/// <summary>
/// 事件的订阅者、事件的发布者
/// </summary>
class Animals
{
    /// <summary>
    /// 定义委托类型
    /// </summary>
    /// <param name="sender">事件的发布者</param>
    /// <param name="e">事件参数类</param>
    public delegate void WowEventHandler(object sender, AnimalEventArgs e);
    /// <summary>
    /// 声明事件
    /// </summary>
    public event WowEventHandler Wow; 
}

构造方法中订阅事件

/// <summary>
/// 事件的订阅者、事件的发布者
/// </summary>
class Animals
{
    /// <summary>
    /// 定义委托类型
    /// </summary>
    /// <param name="sender">事件的发布者</param>
    /// <param name="e">事件参数类</param>
    public delegate void WowEventHandler(object sender, AnimalEventArgs e);
    /// <summary>
    /// 声明事件
    /// </summary>
    public event WowEventHandler Wow;
    /// <summary>
    /// 构造方法,事件绑定方法
    /// </summary>
    public  Animals()
    {
        Wow += this.WOW;
    }
    /// <summary>
    /// 响应事件的函数,事件的订阅方法
    /// </summary>
    /// <param name="sender">事件的发布者</param>
    /// <param name="e">事件参数类</param>
    public void WOW(Object sender, AnimalEventArgs e)
    {
        Console.WriteLine("Animal wow : {0}", e.wow); 
    } 
}

定义 响应 事件的函数。 On开头的函数。(发布者中实现)

/// <summary>
/// 事件的订阅者、事件的发布者
/// </summary>
class Animals
{
    /// <summary>
    /// 定义委托类型
    /// </summary>
    /// <param name="sender">事件的发布者</param>
    /// <param name="e">事件参数类</param>
    public delegate void WowEventHandler(object sender, AnimalEventArgs e);
    /// <summary>
    /// 声明事件
    /// </summary>
    public event WowEventHandler Wow;
    /// <summary>
    /// 构造方法,事件绑定方法
    /// </summary>
    public  Animals()
    {
        Wow += this.WOW;
    }
    /// <summary>
    /// 响应事件的函数,事件的订阅方法
    /// </summary>
    /// <param name="sender">事件的发布者</param>
    /// <param name="e">事件参数类</param>
    public void WOW(Object sender, AnimalEventArgs e)
    {
        Console.WriteLine("Animal wow : {0}", e.wow); 
    }


    /// <summary>
    /// 调用方法触发事件
    /// </summary>
    /// <param name="e">事件参数类</param>
    public virtual void OnWow(AnimalEventArgs e)
    {
        if (Wow != null)
            Wow(this, e);
    }
}

定义 调用 事件函数的 业务逻辑。 (发布者中实现)

class Program
{
    static void Main(string[] args)
    { 
		//初始化,也可以在Cat、Dog类的构造方法中初始化Animals
        Animals animals = new Animals(); 
        Cat cat = new Cat();
        cat.animal = animals;
        Dog dog = new Dog();
        dog.animal = animals; 

        cat.AnimalWow();
        dog.AnimalWow();
         
        Console.ReadKey();
    } 
} 
class Cat
{
    public string wowStr = "喵喵";
    public Animals animal;
    /// <summary>
    /// 让动物叫
    /// </summary>
    public void AnimalWow()
    {
        //事件参数类
        AnimalEventArgs e = new AnimalEventArgs(wowStr);
        animal.OnWow(e);
    }
}
class Dog
{
    public string wowStr = "旺旺";
    public Animals animal;
  
    public void AnimalWow()
    {
        AnimalEventArgs e = new AnimalEventArgs(wowStr);
          animal.OnWow(e);
    }
}

在下面方法中:

	/// <summary>
    /// 调用方法触发事件
    /// </summary>
    /// <param name="e">事件参数类</param>
    public virtual void OnWow(AnimalEventArgs e)
    {
        if (Wow != null)
            Wow(this, e);
    }

这种做法是线程不安全的

if (Wow != null)
	Wow(this, e);

下面是一种安全的做法

    /// <summary>
    /// 调用方法触发事件
    /// </summary>
    /// <param name="e">事件参数类</param>
    public virtual void OnWow(AnimalEventArgs e)
    {
        //临时委托变量,防止多线程移除委托(CLR里提到这是线程不安全的做法,因为单我们判断不为空后,准备执行时,另一个线程将从委托链将委托移除,此时变成了空,引发NullReferenceException异常。)
        WowEventHandler temp = this.Wow;
        if (temp != null)
            temp(this, e);
    }

委托的本质是引用类型,用于包装回调函数,委托用于实现回调机制;事件的本质是委托,事件是回调机制的一种应用。

猜你喜欢

转载自my.oschina.net/MaxWellZhao/blog/1649178