在没有委托变量支持的情况下使用事件有利于哪些情况?

时间:2011-03-14 19:43:38

标签: c# .net events delegates

我正在阅读Jon Skeet的this文章,这是我深入了解代表和事件的一部分。

在文章中,他演示了一个没有委托变量支持的事件,并说明了......

  

...有时候你不想这样做   用简单的委托来支持一个事件   变量。例如,在情况下   那里有很多活动但是   只有少数可能会被订阅   你可以从一些钥匙上得到一张地图   向代表描述事件   目前处理它。这是什么   Windows窗体确实 - 它意味着你   可以举办大量的活动   不浪费大量的记忆   通常只有变量   空值。

我不完全明白他在说什么。有人可以充实这些例子吗?例如,他的意思是“从描述事件的某个键映射到当前处理它的代理”? Windows Forms如何做到这一点?

谢谢!

3 个答案:

答案 0 :(得分:5)

您可以自己使用相同的类型 - EventHandlerList。假设您有100个事件 - 这通常意味着有100个变量,即使没有人订阅过该事件也会占用空间。取而代之的是,EventHandlerList,就像Dictionary<object, EventHandler>一样 - 它只在您第一次订阅特定事件时在其内部数据结构中创建一个条目。

所以你可能有类似的东西:

// Actual values don't matter; they're just keys
private const string FirstEventKey = "FirstEvent";
private const string SecondEventKey = "SecondEvent";

private readonly EventHandlerList events = new EventHandlerList();

public event EventHandler FirstEvent
{
    add { events.AddHandler(FirstEventKey, value); }
    remove { events.RemoveHandler(FirstEventKey, value); }
}

public event EventHandler SecondEvent
{
    add { events.AddHandler(SecondEventKey, value); }
    remove { events.RemoveHandler(SecondEventKey, value); }
}

public void OnFirstEvent(EventArgs e)
{
    EventHandler handler = (EventHandler) events[FirstEventKey];
    if (handler != null)
    {
        handler(this, e);
    }
}

// Similarly for OnSecondEvent

答案 1 :(得分:0)

我想补充一点,这是我经常看到的东西

// bad code
class MyControl : Control {
    public event EventHandler ValueChanged;

    private CheckBox checked;
    // ...

    private void InitializeComponent() {
        // ...
        checked.CheckedChanged += checked_CheckedChanged;
        // ...
    }

    private void checked_CheckedChanged(object sender, EventArgs e) {
        if (ValueChanged != null) {
            ValueChanged(sender, e);
        }
    }
}

我认为这是一种反模式,因为这种方式更快,内存更少,总体上更简单:

class MyControl : Control {
    public event EventHandler ValueChanged {
        add {
            checked.CheckChanged += value;
        }
        remove {
            checked.CheckChanged -= value;
        }
    }

    private CheckBox checked;
    // ...
}

答案 2 :(得分:0)

另一种情况是微不足道的情况,其中基类或接口为某些派生类型中永远不会发生的事件提供事件。例如,只读的observable-collection接口可能提供CollectionChangedEvent。持有接口变量的实体将无法使用它来更改集合,但可能有兴趣知道是否/何时更改了集合。这样的实体应该能够使用不可变集合以及可变集合;从它的角度来看,一个不可变的集合应该就像一个可变的集合,没有人在它正在观看时发生变异。

CollectionChangedEvent最合乎逻辑的实现是使add-and -hand-handler方法不做任何事情,没有支持委托字段。调用add-handler方法的外部实体实质上是说“如果此集合发生更改,请给我打电话”。当它调用remove-handler方法时,它基本上是在说“我不再需要知道这个集合是否会改变”。如果集合永远不会改变,那么这些请求可以通过简单地无所事事来兑现。