模拟C#的事件处理和属性语法糖

1. [代码]SharpEvent.hpp

/*
 * SharpEvent.hpp
 *
 *  Created on: 2014-5-5
 *      Author: leoking
 *   Copyright: This file is published under BSD license.
 *
    Copyright (c) <2014>, <leoking>
    All rights reserved.
 
    Redistribution and use in source and binary forms, with or without
    modification, are permitted provided that the following conditions are met:
        * Redistributions of source code must retain the above copyright
          notice, this list of conditions and the following disclaimer.
        * Redistributions in binary form must reproduce the above copyright
          notice, this list of conditions and the following disclaimer in the
          documentation and/or other materials provided with the distribution.
        * Neither the name of the <organization> nor the
          names of its contributors may be used to endorse or promote products
          derived from this software without specific prior written permission.
 
    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
    ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
    WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
    DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
    DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
    (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
    LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
    ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
    (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
    SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
 
#ifndef SHARPEVENT_HPP_
#define SHARPEVENT_HPP_
 
#include <list>
#include <stdexcept>
 
namespace SharpEvent
{
    template<typename SenderT, typename EventArgsT>
    class CEventHandler
    {
    public:
        typedef SenderT     SenderType;
        typedef EventArgsT  EventArgsType;
 
    private:
        struct holder
        {
            virtual ~holder() {}
            virtual holder* clone() const = 0;
            virtual bool equals(const holder*) const = 0;
            virtual void invoke(SenderType, EventArgsType) const = 0;
        };
 
        struct fholder : public holder
        {
            typedef void (*function)(SenderType, EventArgsType);
            function func;
            fholder(function f) : func(f) {}
            virtual holder* clone() const { return new fholder(func); }
            virtual bool equals(const holder* rhs) const {
                const fholder* p = dynamic_cast<const fholder*>(rhs);
                if (p)
                    return func == p->func;
                else
                    return false;
            }
            virtual void invoke(SenderType a0, EventArgsType a1) const { (*func)(a0, a1); }
        };
 
        template<typename C>
        struct mholder : public holder
        {
            typedef C concept_t;
            typedef void (concept_t::*function)(SenderType, EventArgsType);
            concept_t& obj;
            function func;
            mholder(concept_t* o, function f) : obj(*o), func(f) {}
            virtual holder* clone() const { return new mholder(&obj, func); }
            virtual bool equals(const holder* rhs) const {
                const mholder* p = dynamic_cast<const mholder*>(rhs);
                if (p)
                    return &obj == &(p->obj) && func == p->func;
                else
                    return false;
            }
            virtual void invoke(SenderType a0, EventArgsType a1) const { (obj.*func)(a0, a1); }
        };
 
        holder* h;
 
    public:
        CEventHandler() : h(0) {}
 
        CEventHandler(void(*function)(SenderType, EventArgsType)) : h(0) {
            if (function)
                h = new fholder(function);
        }
 
        template<typename Concept>
        CEventHandler(Concept* object, void(Concept::*function)(SenderType, EventArgsType)) : h(0) {
            if (object && function)
                h = new mholder<Concept>(object, function);
        }
 
        CEventHandler(const CEventHandler& rhs) : h(0) {
            if (rhs.h)
                h = rhs.h->clone();
        }
 
        ~CEventHandler() { delete h; }
 
        void Assign(void(*function)(SenderType, EventArgsType)) {
            Clear();
            if (function)
                h = new fholder(function);
        }
 
        template<typename Concept>
        void Assign(Concept* object, void(Concept::*function)(SenderType, EventArgsType)) {
            Clear();
            if (object && function)
                h = new mholder<Concept>(object, function);
        }
 
        void Assign(const CEventHandler& rhs) {
            if (Equals(rhs))
                return;
            Clear();
            if (rhs.h)
                h = rhs.h->clone();
        }
 
        void Clear() {
            delete h;
            h = 0;
        }
 
        bool Empty() const { return h == 0; }
 
        bool Equals(const CEventHandler& rhs) const {
            if (h && rhs.h)
                return h->equals(rhs.h);
            return false;
        }
 
        void Invoke(SenderType sender, EventArgsType e) const {
            if (h)
                h->invoke(sender, e);
            else
                throw std::runtime_error("Empty EventHandler invoked.");
        }
 
        CEventHandler& operator=(const CEventHandler& rhs) { Assign(rhs); return *this; }
 
        bool operator==(const CEventHandler& rhs) { return Equals(rhs); }
 
        void operator()(SenderType sender, EventArgsType e) const { Invoke(sender, e); }
    };
 
    template<typename DelegateType>
    class CEvent
    {
    public:
        typedef DelegateType EventHandlerType;
        typedef typename EventHandlerType::SenderType       SenderType;
        typedef typename EventHandlerType::EventArgsType    EventArgsType;
 
        CEvent() {}
 
        void operator+=(EventHandlerType handler) { handlers.push_front(handler); handlers.unique(); }
        void operator-=(EventHandlerType handler) { handlers.remove(handler); }
 
        void operator()(SenderType sender, EventArgsType e) {
            for (typename std::list<EventHandlerType>::const_iterator it = handlers.begin();
                    it != handlers.end(); it++)
            {
                EventHandlerType handler = *it;
                handler.Invoke(sender, e);
            }
        }
 
    private:
        std::list<EventHandlerType> handlers;
 
    private:
        CEvent(const CEvent&);
        void operator=(const CEvent&);
    };
}
 
 
#endif /* SHARPEVENT_HPP_ */
2. [代码]SharpProperty.hpp

/*
 * SharpProperty.hpp
 *
 *  Created on: 2014-5-8
 *      Author: leoking
 *   Copyright: This file is published under BSD license.
 *  
    Copyright (c) <2014>, <leoking>
    All rights reserved.
 
    Redistribution and use in source and binary forms, with or without
    modification, are permitted provided that the following conditions are met:
        * Redistributions of source code must retain the above copyright
          notice, this list of conditions and the following disclaimer.
        * Redistributions in binary form must reproduce the above copyright
          notice, this list of conditions and the following disclaimer in the
          documentation and/or other materials provided with the distribution.
        * Neither the name of the <organization> nor the
          names of its contributors may be used to endorse or promote products
          derived from this software without specific prior written permission.
 
    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
    ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
    WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
    DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
    DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
    (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
    LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
    ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
    (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
    SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
 
#ifndef SHARPPROPERTY_HPP_
#define SHARPPROPERTY_HPP_
 
#include <stdexcept>
 
namespace SharpProperty
{
    template<typename T>
    class CGetter
    {
    public:
        typedef T ValueType;
 
    private:
        struct holder
        {
            virtual ~holder() {}
            virtual holder* clone() const = 0;
            virtual bool equals(const holder*) const = 0;
            virtual ValueType invoke() const = 0;
        };
 
        struct fholder : public holder
        {
            typedef ValueType(*function)();
            function func;
            fholder(function f) : func(f) {}
            virtual holder* clone() const { return new fholder(func); }
            virtual bool equals(const holder* rhs) const {
                const fholder* p = dynamic_cast<const fholder*>(rhs);
                if (p)
                    return p->func == func;
                else
                    return false;
            }
            virtual ValueType invoke() const { return (*func)(); }
        };
 
        template<typename Concept>
        struct mholder : public holder
        {http://www.huiyi8.com/hehua/
            typedef Concept concept;?荷花
            typedef ValueType(concept::*function)();
            concept& object;
            function func;
            mholder(concept* o, function f) : object(*o), func(f) {}
            virtual holder* clone() const { return new mholder(&object, func); }
            virtual bool equals(const holder* rhs) const {
                const mholder* p = dynamic_cast<const mholder*>(rhs);
                if (p)
                    return &(p->object) == &object && p->func == func;
                else
                    return false;
            }
            virtual ValueType invoke() const { return (object.*func)(); }
        };
 
        holder* h;
 
    public:
        CGetter(ValueType (*function)()) : h(0) {
            if (function)
                h = new fholder(function);
        }
 
        template<typename Concept>
        CGetter(Concept* object, ValueType(Concept::*function)()) : h(0) {
            if (object && function)
                h = new mholder<Concept>(object, function);
        }
 
        CGetter(const CGetter& rhs) {
            if (rhs.h)
                h = rhs.h->clone();
        }
 
        ~CGetter() { delete h; }
 
        ValueType Invoke() const {
            if (h)
                return h->invoke();
            else
                throw std::runtime_error("Empty Getter invoked.");
        }
 
    private:
        void operator=(const CGetter&);
    };
 
    template<typename T>
    class CSetter
    {
    public:
        typedef T ValueType;
 
    private:
        struct holder
        {
            virtual ~holder() {}
            virtual holder* clone() const = 0;
            virtual bool equals(const holder*) const = 0;
            virtual void invoke(ValueType) const = 0;
        };
 
        struct fholder : public holder
        {
            typedef void(*function)(ValueType);
            function func;
            fholder(function f) : func(f) {}
            virtual holder* clone() const { return new fholder(func); }
            virtual bool equals(const holder* rhs) const {
                const fholder* p = dynamic_cast<const fholder*>(rhs);
                if (p)
                    return p->func == func;
                else
                    return false;
            }
            virtual void invoke(ValueType value) const { (*func)(value); }
        };
 
        template<typename Concept>
        struct mholder : public holder
        {
            typedef Concept concept;
            typedef void(concept::*function)(ValueType);
            concept& object;
            function func;
            mholder(concept* o, function f) : object(*o), func(f) {}
            virtual holder* clone() const { return new mholder(&object, func); }
            virtual bool equals(const holder* rhs) const {
                const mholder* p = dynamic_cast<const mholder*>(rhs);
                if (p)
                    return &(p->object) == &object && p->func == func;
                else
                    return false;
            }
            virtual void invoke(ValueType value) const { (object.*func)(value); }
        };
 
        holder* h;
 
    public:
        CSetter(void (*function)(ValueType)) : h(0) {
            if (function)
                h = new fholder(function);
        }
 
        template<typename Concept>
        CSetter(Concept* object, void(Concept::*function)(ValueType)) : h(0) {
            if (object && function)
                h = new mholder<Concept>(object, function);
        }
 
        CSetter(const CSetter& rhs) {
            if (rhs.h)
                h = rhs.h->clone();
        }
 
        ~CSetter() { delete h; }
 
        void Invoke(ValueType value) const {
            if (h)
                h->invoke(value);
            else
                throw std::runtime_error("Empty Setter invoked.");
        }
 
    private:
        void operator=(const CSetter&);
    };
 
    template<typename T>
    class property
    {
    public:
        typedef T ValueType;
 
        property() : getter(0), setter(0) {}
        ~property() { delete getter; delete setter; }
 
        void operator()(ValueType (*getter)(), void (*setter)(ValueType)) {
            if (getter)
                this->getter = new CGetter<ValueType>(getter);
            if (setter)
                this->setter = new CSetter<ValueType>(setter);
        }
 
        void operator()(ValueType (*getter)()) {
            this->operator()(getter, 0);
        }
 
        void operator()(void (*setter)(ValueType)) {
            this->operator()(0, setter);
        }
 
        template<typename Concept>
        void operator()(Concept* object, ValueType (Concept::*getter)(), void (Concept::*setter)(ValueType)) {
            if (object == 0)
                throw std::invalid_argument("Property initialized with null object.");
            if (getter)
                this->getter = new CGetter<ValueType>(object, getter);
            if (setter)
                this->setter = new CSetter<ValueType>(object, setter);
        }
 
        template<typename Concept>
        void operator()(Concept* object, ValueType (Concept::*getter)()) {
            this->operator()<Concept>(object, getter, 0);
        }
 
        template<typename Concept>
        void operator()(Concept* object, void (Concept::*setter)(ValueType)) {
            this->operator()<Concept>(object, 0, setter);
        }
 
        operator ValueType() {
            if (getter == 0)
                throw std::runtime_error("Property without getter is not readable.");
            return getter->Invoke();
        }
 
        void operator=(ValueType value) {
            if (setter == 0)
                throw std::runtime_error("Property without setter is not assignable.");
            setter->Invoke(value);
        }
 
    private:
        CGetter<ValueType>* getter;
        CSetter<ValueType>* setter;
 
        property(const property&);
    };
}
 
#endif /* SHARPPROPERTY_HPP_ */
3. [代码]Sample.cpp

#include "SharpEvent.hpp"
#include "SharpProperty.hpp"
#include <string>
#include <iostream>
 
class CPerson;
 
using SharpProperty::property;
typedef SharpEvent::CEventHandler<CPerson*, double> EventHandler;
typedef SharpEvent::CEvent<EventHandler> event;
 
class CPerson
{
public:
    // enum:
    enum SexFlag { FEMALE, MALE };
     
    CPerson(const std::string& name, int age, SexFlag sex, double tall)
        : name(name), age(age), sex(sex), tall(tall)
    {
        Name(this, &CPerson::getName, &CPerson::setName);
        Age(this, &CPerson::getAge, &CPerson::setAge);
        Sex(this, &CPerson::getSex); // Sex property can not be modified.
        Tall(this, &CPerson::getTall, &CPerson::setTall);
    }
     
    // property:
    property<std::string> Name;
    property<int> Age;
    property<SexFlag> Sex;
    property<double> Tall;
     
    // event:
    event Growth;
         
private:
    // field:
    std::string name;
    int age;
    SexFlag sex;
    double tall;
     
    // getter-setter:
    std::string getName() { return name; }
    void setName(std::string value) { name = value; }
     
    int getAge() { return age; }
    void setAge(int value) { age = value; }
     
    SexFlag getSex() { return sex; }
    //void setSex(SexFlag value) { sex = value; }
     
    double getTall() { return tall; }
    void setTall(double value) {
        tall = value;
        Growth(this, tall);
    }
};
 
void OnGrowth(CPerson* sender, double e) {
    std::cout << "Person named " << (std::string)sender->Name
            << " has grown to " << e << " cm."
            << std::endl;
}
 
int main()
{
    CPerson person("LiMing", 20, CPerson::MALE, 173.4);
    person.Growth += EventHandler(&OnGrowth);
    person.Tall = 174;
}

时间: 2024-10-30 06:14:10

模拟C#的事件处理和属性语法糖的相关文章

Zepto源码分析-event模块

源码注释 // Zepto.js // (c) 2010-2015 Thomas Fuchs // Zepto.js may be freely distributed under the MIT license. ;(function($){ var _zid = 1, undefined, slice = Array.prototype.slice, isFunction = $.isFunction, isString = function(obj){ return typeof obj

JavaScript之jQuery-4 jQuery事件(页面加载后执行、事件处理、事件冒泡、事件对象、模拟操作)

一.jQuery 页面加载后执行 代码执行的时机选择 - $(document).ready()方法和 window.onload事件具有相似的功能,但是在执行时机方面是有区别的 - window.onload 事件是在网页中所有的元素(包括元素的所有关联文件)完全加载到浏览器后才执行 - $(document).ready()方法注册的事件处理程序,在DOM完全加载后就可以调用 - 一般来讲, $(document).ready()的执行要优于window.onload事件 - 需要注意的是,

selenium模拟事件处理

执行原理: 调用ActionChains的方法时不会立即执行,会将所有的操作按顺序存放在一个队列里,当调用perform()方法时,从队列中的事件会依次执行. 支持链式写法或者是分布写法. 鼠标键盘方法列表: perform() 执行链中的所有动作 click(on_element=None) 单击鼠标左键 context_click(on_element=None) 单击鼠标右键 move_to_element(to_element) 鼠标移动到某个元素 ele.send_keys(keys_

半糖iOS版首页实现与基本原理揭秘

很久以前,一个学弟的曾问过我如何实现半糖iOS版本首页效果,我当时一看觉得这个效果挺酷炫,然后去github上搜了一下,很多自称是仿半糖首页的,我下载之后发现其实很多代码都没有实现主要的代码.有些代码也做了一些简单的尝试,但是最后都放弃了,所以说这个效果还是没有很好的实现.我于是打算研究一下这个有趣的效果,经过工作之余一段时间的研究.有时候路上也会想一想,做了很多的尝试,一点一点的把遇到的问题解决了.于是写下这篇文章,把自己的一些尝试和想法与大家分享. 有的开发者可能会觉得这么简单的东西别拿来忽

jQuery事件处理

1.使用jQuery实现事件绑定 语法: $obj.bind(事件类型,事件处理函数) 如: $obj.bink('click',fn); 简写形式 $obj,click(fn); 注: $obj.click()则代表触发了click事件. 2.获得事件对象event 只需要为事件处理函数传递任意一个参数 如: $obj.click(function(e){...}) e就是事件对象,但已经经过jQuery对底层事件对象的封装 封装后的事件对象可以方便的兼容各浏览器 3.事件对象常用的属性 获取

HDU-1034-Candy Sharing Game(C++ &amp;&amp; 简单模拟)

Candy Sharing Game Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 3703    Accepted Submission(s): 2311 Problem Description A number of students sit in a circle facing their teacher in the cent

谈一谈jquery中的事件处理

①jQuery内置事件函数的两种声明方式 不带参数的事件函数-事件类型名() 模拟了用户的操作 带参数的事件函数-事件类型名(事件函数) $($("#id").click(function(){})) 带参数的事件函数 $($("#id").click(function(){}); $("#id").click();) 不带参数的事件函数-不单击#id也会执行相应函数 即模拟了用户操作 ②jQuery内置事件类型分类 ⑴浏览器相关事件 error

C#十种语法糖

语法糖 指计算机语言中添加的某种语法,这种语法对语言的功能并没有影响,但是更方便程序员使用.通常来说使用语法糖能够增加程序的可读性,从而减少程序代码出错的机会.需要声明的是"语法糖"这个词绝非贬义词,它可以给我们带来方便,是一种便捷的写法,编译器会帮我们做转换,而且可以提高开发编码的效率,在性能上也不会带来损失. 一.自动属性 以前:手写私有变量+公有属性现在:声明空属性,编译器自动生成对应私有成员字段. 写法:输入prop ,连续按两次tab键,自动生成属性. 1 /// <s

jquery事件之事件处理函数

一.事件处理 方法名 说明 语法 (events 事件类型,data数据,handler 事件处理函数,selector 选择器) Bind( 为每一个匹配元素的特定事件(像click)绑定一个事件处理器函数.没用on关键字 jQueryObject.bind( events [, data ], handler ) One 为每一个匹配元素的特定事件(像click)绑定一个一次性的事件处理函数.只绑定一次 jQueryObject.one( events [, data ], handler