zoukankan      html  css  js  c++  java
  • 用 C# 做组件设计时的事件实现方法讨论

    事件,其实就是将物体的某个过程处理通过委托(delegate, 也就是函数指针) 的方式公开给外部的自定义函数处理。 C# 可以使用多播委托,但实际上一般情况下只需要用到单播。

    事件需要通过调用到那个委托的代码触发才可以被调用。
    以下用例子来说明。首先我们定义一个委托:

    namespace EventDemo
    {
        public delegate void ProcessHandler(object sender);
    }
    

    最简单的事件定义方式:
    namespace EventDemo
    {
        public class Class1
        {
            private event ProcessHandler _processHandler = null;
            public event ProcessHandler ProcessStart
            {
                add { _processHandler += value; }
                remove { _processHandler -= value; }
            }
            /// 
            /// 触发事件的某个方法
            /// 
            public void Process()
            {
                _processHandler(this);
                for (int i = 0; i < 10; i++)
                    i = i + 1;
            }
            public Class1()
            {
            }
        }
    }
    

    Class1 使用原始的事件定义方式, 有一个问题,如果事件非常多的时候,每一个事件都要对应一个相应的私有的委托成员(函数指针)。在窗口程序里尤其可怕,因为 Windows 窗口消息数以千计。这样会造成很庞大的内存消耗。
    这个模式需要改进为 Class2。代码如下:

    namespace EventDemo
    {
        using System.Collections;
        public class Class2
        {
            private Hashtable _eventList = new Hashtable();
            // 每一种事件会对应一个相应的静态变量作为他们在 Hashtable 中的 keys.
            private static object _processStart = new object();
            private static object _processEnd = new object();
            public event ProcessHandler ProcessStart
            {
                add { _eventList.Add(_processStart, value); }
                remove { _eventList.Remove(_processStart); }
            }
            public event ProcessHandler ProcessEnd
            {
                add { _eventList.Add(_processEnd, value); }
                remove { _eventList.Remove(_processEnd); }
            }
            public void Process()
            {
                ProcessHandler start = (ProcessHandler) _eventList[_processStart];
                ProcessHandler end = (ProcessHandler) _eventList[_processEnd];
                if (start != null)
                    start(this);
                for (int i = 0; i < 10; i++)
                    i = i + 1;
                if (end != null)
                    end(this);
            }
            public Class2()
            {
            }
        }
    }
    

    Class2 中,每一种事件定义一个相应的静态变量作为他们在 Hashtable 中的 keys.
    Hashtable 作为函数指针的容器,是私有的。
    这样实际上是 Lazy Allocate 模式,大大减小了内存的开销。
    但该实现也有问题,因为每个 key 只对应一个 value,所以不能支持 multicast 的事件。

    在 .net 中,通常继承自 Component 类来实现这种基础架构。代码如下:

    namespace EventDemo
    {
        using System;
        using System.ComponentModel;
        public class Class3 : Component
        {
            private static object _processStart = new object();
            public event EventHandler ProcessStart
            {
                add { Events.AddHandler(_processStart, value); }
                remove { Events.RemoveHandler(_processStart, value); }
            }
            public void Process()
            {
                EventHandler handler = (EventHandler) Events[_processStart];
                if (handler != null)
                    handler(this, null);
            }
            public Class3()
            {
            }
        }
    }
    

    Component 类的实现是完整的,支持 Multicast 委托。我们用 Reflector 看一下该类的代码,会看到有一个叫做 EventHandlerList 的类,代码如下:

    public sealed class EventHandlerList : IDisposable
    {
        // Methods
        public EventHandlerList()
        {
        }
     
        public void AddHandler(object key, Delegate value)
        {
            EventHandlerList.ListEntry entry1 = this.Find(key);
            if (entry1 != null)
            {
                entry1.handler = Delegate.Combine(entry1.handler, value);
            }
            else
            {
                this.head = new EventHandlerList.ListEntry(key, value, this.head);
            }
        }
     
        public void Dispose()
        {
            this.head = null;
        }
         
        private EventHandlerList.ListEntry Find(object key)
        {
            EventHandlerList.ListEntry entry1 = this.head;
            while (entry1 != null)
            {
                if (entry1.key == key)
                {
                    break;
                }
                entry1 = entry1.next;
            }
            return entry1;
        }
     
        public void RemoveHandler(object key, Delegate value)
        {
            EventHandlerList.ListEntry entry1 = this.Find(key);
            if (entry1 != null)
            {
                entry1.handler = Delegate.Remove(entry1.handler, value);
            }
        }
        // Properties
        public Delegate this[object key]
        {
            get
            {
                EventHandlerList.ListEntry entry1 = this.Find(key);
                if (entry1 != null)
                {
                    return entry1.handler;
                }
                return null;
            }
            set
            {
                EventHandlerList.ListEntry entry1 = this.Find(key);
                if (entry1 != null)
                {
                    entry1.handler = value;
                }
                else
                {
                    this.head = new EventHandlerList.ListEntry(key, value, this.head);
                }
            }
        }
        // Fields
        private ListEntry head;
        // Nested Types
        private sealed class ListEntry
        {
            // Methods
            public ListEntry(object key, Delegate handler, EventHandlerList.ListEntry next)
            {
                this.next = next;
                this.key = key;
                this.handler = handler;
            }
            // Fields
            internal Delegate handler;
            internal object key;
            internal EventHandlerList.ListEntry next;
        }
    }
    

    这个类实现了一个事件的链表数据结构。其中每一个具体的事件是采用 Delegate.Combine(), Delegate.Remove() 方法来添加和删除具体的 delegate. 所以这个的实现和 Class2 的实现相比功能更加完整了。

    Component 类的代码是这样的:

    [DesignerCategory("Component")]
    public class Component : MarshalByRefObject, IComponent, IDisposable
    {
        private EventHandlerList events;
        protected EventHandlerList Events
        {
            get
            {
                if (this.events == null)
                {
                    this.events = new EventHandlerList();
                }
                return this.events;
            }
        }
        // ...
    }
    

    它简单的通过提供 Events 这个属性,让设计者可以自由的实现各种属性。

    (注:本文的 Class1 ~ Class3 代码范例来自黄忠成的《深入剖析 asp.net 组件设计》一书。)
  • 相关阅读:
    城市的划入划出效果
    文本溢出省略解决笔记css
    长串英文数字强制折行解决办法css
    Poj 2352 Star
    树状数组(Binary Indexed Trees,二分索引树)
    二叉树的层次遍历
    Uva 107 The Cat in the Hat
    Uva 10336 Rank the Languages
    Uva 536 Tree Recovery
    Uva10701 Pre, in and post
  • 原文地址:https://www.cnblogs.com/RChen/p/265575.html
Copyright © 2011-2022 走看看