其实要改成真正的C#版,我们主要要做2件事, 一是吧CEventHandler放到外面,可以让外部直接构造, 二是实现operator +=和operator -=, 下面是我的实现代码:
#pragma once
#include <functional>
#include <algorithm>
#include <vector>
#include <assert.h>
namespace Common
{
typedef void * cookie_type;
template<typename TR, typename T1, typename T2>
class CEventHandler
{
public :
typedef TR return_type;
typedef T1 first_type;
typedef T2 second_type;
typedef std::function<return_type (first_type, second_type)> handler_type;
CEventHandler( const CEventHandler& h)
{
_handler = h._handler;
assert(_handler != nullptr);
}
CEventHandler(handler_type h)
{
_handler = h;
assert(_handler != nullptr);
}
template<typename class_type, typename class_fun>
CEventHandler(class_type* pThis, class_fun object_function)
{
using namespace std::placeholders;
_handler = std::bind(object_function, pThis, _1, _2);
assert(_handler != nullptr);
}
return_type operator ()(first_type p1, second_type p2)
{
return_type ret = return_type();
assert(_handler != nullptr);
if (_handler != nullptr) ret = _handler(p1, p2);
return ret;
}
handler_type _handler;
};
template<typename EventHandler>
class CEvent
{
public :
typedef EventHandler event_handler_type;
typedef typename event_handler_type::return_type return_type;
typedef typename event_handler_type::first_type first_type;
typedef typename event_handler_type::second_type second_type;
typedef typename event_handler_type::handler_type handler_type;
~CEvent()
{
Clear();
}
return_type operator ()(first_type p1, second_type p2)
{
return_type ret = return_type();
size_t size = _handlers.size();
for (auto p : _handlers)
{
ret = p-> operator ()(p1, p2);
}
return ret;
}
cookie_type AddHandler( const event_handler_type& h)
{
event_handler_type*p = new (nothrow) event_handler_type(h);
if (p != nullptr) _handlers.push_back(p);
return (cookie_type)p;
}
void RemoveHandler(cookie_type cookie)
{
event_handler_type* p = (event_handler_type*)cookie;
auto itr = std::find(_handlers.begin(), _handlers.end(), p);
if (itr != _handlers.end())
{
_handlers.erase(itr);
delete p;
}
else
{
assert( false );
}
}
cookie_type operator += ( const event_handler_type& pHandler)
{
return AddHandler(pHandler);
}
void operator -= (cookie_type cookie)
{
RemoveHandler(cookie);
}
void Clear()
{
if (!_handlers.empty())
{
int n = _handlers.size();
std::for_each(_handlers.begin(), _handlers.end(), [](event_handler_type* p)
{
assert(p != nullptr);
delete p;
});
_handlers.clear();
}
}
private :
std::vector<event_handler_type*> _handlers;
};
} // Common
#include <functional>
#include <algorithm>
#include <vector>
#include <assert.h>
namespace Common
{
typedef void * cookie_type;
template<typename TR, typename T1, typename T2>
class CEventHandler
{
public :
typedef TR return_type;
typedef T1 first_type;
typedef T2 second_type;
typedef std::function<return_type (first_type, second_type)> handler_type;
CEventHandler( const CEventHandler& h)
{
_handler = h._handler;
assert(_handler != nullptr);
}
CEventHandler(handler_type h)
{
_handler = h;
assert(_handler != nullptr);
}
template<typename class_type, typename class_fun>
CEventHandler(class_type* pThis, class_fun object_function)
{
using namespace std::placeholders;
_handler = std::bind(object_function, pThis, _1, _2);
assert(_handler != nullptr);
}
return_type operator ()(first_type p1, second_type p2)
{
return_type ret = return_type();
assert(_handler != nullptr);
if (_handler != nullptr) ret = _handler(p1, p2);
return ret;
}
handler_type _handler;
};
template<typename EventHandler>
class CEvent
{
public :
typedef EventHandler event_handler_type;
typedef typename event_handler_type::return_type return_type;
typedef typename event_handler_type::first_type first_type;
typedef typename event_handler_type::second_type second_type;
typedef typename event_handler_type::handler_type handler_type;
~CEvent()
{
Clear();
}
return_type operator ()(first_type p1, second_type p2)
{
return_type ret = return_type();
size_t size = _handlers.size();
for (auto p : _handlers)
{
ret = p-> operator ()(p1, p2);
}
return ret;
}
cookie_type AddHandler( const event_handler_type& h)
{
event_handler_type*p = new (nothrow) event_handler_type(h);
if (p != nullptr) _handlers.push_back(p);
return (cookie_type)p;
}
void RemoveHandler(cookie_type cookie)
{
event_handler_type* p = (event_handler_type*)cookie;
auto itr = std::find(_handlers.begin(), _handlers.end(), p);
if (itr != _handlers.end())
{
_handlers.erase(itr);
delete p;
}
else
{
assert( false );
}
}
cookie_type operator += ( const event_handler_type& pHandler)
{
return AddHandler(pHandler);
}
void operator -= (cookie_type cookie)
{
RemoveHandler(cookie);
}
void Clear()
{
if (!_handlers.empty())
{
int n = _handlers.size();
std::for_each(_handlers.begin(), _handlers.end(), [](event_handler_type* p)
{
assert(p != nullptr);
delete p;
});
_handlers.clear();
}
}
private :
std::vector<event_handler_type*> _handlers;
};
} // Common
然后我们就可以这样使用了:
//
EventTest.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <iostream>
#include "event2.h"
using namespace std;
class CObjectX
{
};
class CClickEventArgs: public CObjectX
{
};
class CButton: public CObjectX
{
public :
void FireClick()
{
CClickEventArgs args;
OnClicked( this , args);
}
typedef Common::CEventHandler< int , CObjectX*, CClickEventArgs&> ButtonClickEventHandler;
Common::CEvent<ButtonClickEventHandler> OnClicked;
};
class CMyClass
{
public :
int OnBtuttonClicked(CObjectX* pButton, CClickEventArgs& args)
{
cout << "CMyClass: Receive button clicked event" << endl;
return 1;
}
};
int OnBtuttonClicked_C_fun(CObjectX* pButton, CClickEventArgs& args)
{
cout << "C Style Function: Receive button clicked event" << endl;
return 1;
}
class CMyFunObj
{
public :
int operator ()(CObjectX* pButton, CClickEventArgs& args)
{
cout << "Functor: Receive button clicked event" << endl;
return 1;
}
};
int _tmain( int argc, _TCHAR* argv[])
{
CButton btn;
CMyClass obj;
Common::cookie_type c1 = btn.OnClicked += CButton::ButtonClickEventHandler(&obj, &CMyClass::OnBtuttonClicked);
Common::cookie_type c2 = btn.OnClicked += CButton::ButtonClickEventHandler(OnBtuttonClicked_C_fun);
CMyFunObj functor;
Common::cookie_type c3 = btn.OnClicked += CButton::ButtonClickEventHandler(functor);
btn.FireClick();
btn.OnClicked -= c2;
std::cout << endl;
btn.FireClick();
system("pause");
return 0;
}
//
#include "stdafx.h"
#include <iostream>
#include "event2.h"
using namespace std;
class CObjectX
{
};
class CClickEventArgs: public CObjectX
{
};
class CButton: public CObjectX
{
public :
void FireClick()
{
CClickEventArgs args;
OnClicked( this , args);
}
typedef Common::CEventHandler< int , CObjectX*, CClickEventArgs&> ButtonClickEventHandler;
Common::CEvent<ButtonClickEventHandler> OnClicked;
};
class CMyClass
{
public :
int OnBtuttonClicked(CObjectX* pButton, CClickEventArgs& args)
{
cout << "CMyClass: Receive button clicked event" << endl;
return 1;
}
};
int OnBtuttonClicked_C_fun(CObjectX* pButton, CClickEventArgs& args)
{
cout << "C Style Function: Receive button clicked event" << endl;
return 1;
}
class CMyFunObj
{
public :
int operator ()(CObjectX* pButton, CClickEventArgs& args)
{
cout << "Functor: Receive button clicked event" << endl;
return 1;
}
};
int _tmain( int argc, _TCHAR* argv[])
{
CButton btn;
CMyClass obj;
Common::cookie_type c1 = btn.OnClicked += CButton::ButtonClickEventHandler(&obj, &CMyClass::OnBtuttonClicked);
Common::cookie_type c2 = btn.OnClicked += CButton::ButtonClickEventHandler(OnBtuttonClicked_C_fun);
CMyFunObj functor;
Common::cookie_type c3 = btn.OnClicked += CButton::ButtonClickEventHandler(functor);
btn.FireClick();
btn.OnClicked -= c2;
std::cout << endl;
btn.FireClick();
system("pause");
return 0;
}
怎么样,是不是感觉和C#一样了 !
最后,我们比较一下2种实现方式:
第一种方法把委托函数类型封装起来了,对外部来说是透明的, 使用起来更简单。
第二种方式把委托函数的类型暴露了出来, 适用于 事件处理函数类型各异, 比较强调事件处理函数类型的场合。
其实对于C++来说,个人觉得还是第一种方式更合理, 不知道大家怎么看?
注: 如果你不想用C++11的新特性或是你手头的编译器不支持C++11, 下面是一种不借助function和bind的实现方式,
直接用下面的CEventHandler替代上面的就可以了。
一种不借助C++11 function和bind的实现方式
template<typename TR, typename T1, typename T2>
class CEventHandler
{
public:
typedef TR return_type;
typedef T1 first_type;
typedef T2 second_type;
private:
class CFunctionBase
{
public:
virtual return_type Invoke(first_type p1, second_type p2) = 0;
virtual CFunctionBase* Clone() = 0;
virtual ~CFunctionBase() { }
};
template<typename TFunType>
class CFunction: public CFunctionBase
{
public:
CFunction( const TFunType& f): _f(f) { }
virtual return_type Invoke(first_type p1, second_type p2)
{
return _f(p1, p2);
}
virtual CFunctionBase* Clone()
{
return new CFunction( this->_f);
}
private:
TFunType _f;
};
template<typename TClassPtr, typename TMemFunType>
class CClassMemFun: public CFunctionBase
{
public:
CClassMemFun(TClassPtr pObj, const TMemFunType& f): _pObj(pObj), _pMemFun(f) { }
virtual return_type Invoke(first_type p1, second_type p2)
{
return ((*_pObj).*_pMemFun)(p1, p2);
}
virtual CFunctionBase* Clone()
{
return new CClassMemFun( this->_pObj, this->_pMemFun);
}
private:
TClassPtr _pObj;
TMemFunType _pMemFun;
};
public:
template<typename TFunType>
CEventHandler( const TFunType& f): _pFun( new CFunction<TFunType>(f)) { }
template<typename TClassPtr, typename TMemFunType>
CEventHandler(TClassPtr pObj, TMemFunType pFun): _pFun( new CClassMemFun<TClassPtr, TMemFunType>(pObj, pFun)) { }
CEventHandler( const CEventHandler& f)
{
_pFun = f._pFun->Clone();
}
~CEventHandler()
{
delete _pFun;
}
CEventHandler& operator = ( const CEventHandler& f)
{
if( this != &f)
{
delete _pFun;
_pFun = f._pFun->Clone();
}
return * this;
}
return_type operator()(first_type p1, second_type p2)
{
return_type ret = return_type();
if(_pFun != nullptr)
{
_pFun->Invoke(p1, p2);
}
else
{
assert( false);
}
return ret;
}
private:
CFunctionBase* _pFun;
class CEventHandler
{
public:
typedef TR return_type;
typedef T1 first_type;
typedef T2 second_type;
private:
class CFunctionBase
{
public:
virtual return_type Invoke(first_type p1, second_type p2) = 0;
virtual CFunctionBase* Clone() = 0;
virtual ~CFunctionBase() { }
};
template<typename TFunType>
class CFunction: public CFunctionBase
{
public:
CFunction( const TFunType& f): _f(f) { }
virtual return_type Invoke(first_type p1, second_type p2)
{
return _f(p1, p2);
}
virtual CFunctionBase* Clone()
{
return new CFunction( this->_f);
}
private:
TFunType _f;
};
template<typename TClassPtr, typename TMemFunType>
class CClassMemFun: public CFunctionBase
{
public:
CClassMemFun(TClassPtr pObj, const TMemFunType& f): _pObj(pObj), _pMemFun(f) { }
virtual return_type Invoke(first_type p1, second_type p2)
{
return ((*_pObj).*_pMemFun)(p1, p2);
}
virtual CFunctionBase* Clone()
{
return new CClassMemFun( this->_pObj, this->_pMemFun);
}
private:
TClassPtr _pObj;
TMemFunType _pMemFun;
};
public:
template<typename TFunType>
CEventHandler( const TFunType& f): _pFun( new CFunction<TFunType>(f)) { }
template<typename TClassPtr, typename TMemFunType>
CEventHandler(TClassPtr pObj, TMemFunType pFun): _pFun( new CClassMemFun<TClassPtr, TMemFunType>(pObj, pFun)) { }
CEventHandler( const CEventHandler& f)
{
_pFun = f._pFun->Clone();
}
~CEventHandler()
{
delete _pFun;
}
CEventHandler& operator = ( const CEventHandler& f)
{
if( this != &f)
{
delete _pFun;
_pFun = f._pFun->Clone();
}
return * this;
}
return_type operator()(first_type p1, second_type p2)
{
return_type ret = return_type();
if(_pFun != nullptr)
{
_pFun->Invoke(p1, p2);
}
else
{
assert( false);
}
return ret;
}
private:
CFunctionBase* _pFun;