Sheen Space

Posts Tagged ‘callback

回调(Callback), 委托(Delegate), 事件(Event)

leave a comment »

本文通过认识Observer Pattern,以及对比C++,C#对这个模式的实现来理解C#中的委托(delegate)和事件(event)。

Observer Pattern设计模式

http://en.wikipedia.org/wiki/Observer_pattern Observer Pattern绝不是什么新东西。大家能想到的最早最低级别的实际例子是什么?Intel x86系统中的中断向量表是我能想到的最低级别的实现。整个计算机就是subject,可以随时产生各种事件,INT指令就是事件触发,中断向量表中对应的中断处理函数就是observer对特定事件的反应。 下面是我写的两个小例子程序,用来演示Observer Pattern在C++和C#中是如何实现的。只是一个概念展示,程序不见得有实际用途。两个程序类似,都定义了一个class Subject,和对应的两个Observer。很容易看懂,就不做解释了。

回调函数(C++)

#include <iostream>
#include <list>
#include <algorithm>
using namespace std;

// Subject class that accepts callback function pointer
class Subject
{
	// Type declaration
	// Define Callback function type, which is essentially function pointer
	typedef void (*Callback)(void* subject, void* arg);
private:
	// List of Callback function pointers 
	list<Callback> _callbacks;
public:
	void RegisterNotification(Callback callback)
	{
		list<Callback>::iterator it = find(_callbacks.begin(), _callbacks.end(), callback);
		if (it == _callbacks.end())
			_callbacks.push_back(callback);
	}
	
	void UnregisterNotification(Callback callback)
	{
		list<Callback>::iterator it = find(_callbacks.begin(), _callbacks.end(), callback);
		if (it != _callbacks.end())
			_callbacks.erase(it);
	}
	
	// Invoke all callback functions
	void Notify()
	{
		if (_callbacks.empty())
			cout << "Nobody to notify" << endl;
		
		for (list<Callback>::iterator it = _callbacks.begin(); it != _callbacks.end(); ++it)
			(*it)(this, 0);
	}
	
	void Run()
	{
		// Do some work
		Notify();
	}
};

// Concrete observer
class Observer1
{
public:
	static void Notify(void* subject, void* arg)
	{
		cout << "Observer1 notified" << endl;
	}
};

// Concrete observer
class Observer2
{
public:
	static void Notify(void* subject, void* arg)
	{
		cout << "Observer2 notified" << endl;
	}
};

int main(int argc, char* argv[])
{
	Subject subject;
	
	subject.RegisterNotification(Observer1::Notify);
	subject.RegisterNotification(Observer2::Notify);
	
	subject.Run();
	
	subject.UnregisterNotification(Observer1::Notify);
	subject.UnregisterNotification(Observer2::Notify); subject.Run();
	
	return 0;
}

委托和事件(C#)

using System;
using System.Collections.Generic;
using System.Text;

namespace ObserverCs
{
	// Subject class that accepts callback function pointer
	class Subject
	{
		// Type declaration
		// Define Callback function type, which is essentially function pointer
		public delegate void Callback(object subject, object arg);
		
		// Event object public event Callback C;
		public void Run()
		{
			// Do some work
			if (C != null)
				C.Invoke(this, null);
			else Console.WriteLine("Nobody to notify");
		}
	}
	
	// Concrete observer
	class Observer1
	{
		public static void Notify(object subject, object arg)
		{
			Console.WriteLine("Observer1 notified");
		}
	}
	
	// Concrete observer
	class Observer2
	{
		public static void Notify(object subject, object arg)
		{
			Console.WriteLine("Observer2 notified");
		}
	}
	
	class Program
	{
		static void Main(string[] args)
		{
			Subject subject = new Subject();
			subject.C += Observer1.Notify;
			subject.C += Observer2.Notify;
			
			subject.Run();
			
			subject.C -= Observer1.Notify;
			subject.C -= Observer2.Notify;
			
			subject.Run();
		}
	}
}

C#委托和事件辨析

有些C#初学者对于委托和事件的理解不够明晰深刻。通过认识Observer Pattern和上面两个例子代码的对比,应该认识就会很深刻了。下面我们把两个例子中的关键代码行放在一起仔细对比一下:

// C++
typedef void (*Callback)(void* subject, void* arg);
// C#
delegate void Callback(object subject, object arg);

// C++
list&lt;Callback&gt; _callbacks;
// C#
event Callback C;

// C++
subject.RegisterNotification(Observer1::Notify);
// C#
subject.C += Observer1.Notify;

委托就是对拥有相同签名的函数/方法的类型定义;事件就是委托实例的集合,包含0个或多个委托函数实例。事件这个名字稍微有点迷惑性。他更多的表达的是这个委托集合在应用上的一般目的(处理事件)。

Written by Ying

21/09/2010 at 14:29