2010-10-15 65 views
25

考慮下面的代碼:調用多態場式的事件

public class TableMain { 
    public virtual event Action UpdateFilter; 
    .... 
} 

public class TableSub : TableMain { 
    public override event Action UpdateFilter; 

    public void UpdateQuery() { 
     ..... 
     if (UpdateFilter!=null) { 
       UpdateFilter(); // Invocation of polymorphic field-like event??? 
     } 
    } 
} 

在這段代碼ReSharper顯示警報「多態場式的事件調用」。

我的問題是: 這實際上是什麼意思?這是一個糟糕的編程習慣的警報? 另外,多態地調用一個事件是不好的做法? (知道一個事件只能從宣佈它的類中提出)。

回答

41

那麼,你實際上得到了兩個這裏的場類事件。你的覆蓋將覆蓋添加/刪除部分,但你會有兩個字段 - 一個在TableMain和一個在TableSub。除非在TableMain中明確設置了值,否則只有TableSub中的一個非空,因此如果TableMain曾嘗試提升事件本身,它將不會調用與TableSub中相同的處理程序集。基本上,它會表現得很奇怪。

正確的方法是在TableMain提供一個受保護的方法,以允許由子類引發事件:

protected void OnUpdateFilter() 
{ 
    Action handler = UpdateFilter; 
    if (handler != null) 
    { 
     handler(); 
    } 
} 

然後使該事件非虛擬和除去覆蓋在TableSub

請注意,您的活動簽名與活動的常規約定不符 - 因爲沒有使用EventHandler

+0

這聽起來像是一個很大的潛在錯誤來源,因爲它很可能不是您在編寫此類代碼時所期望的。以前從來沒有必要去思考這個特定的方面。你知道爲什麼虛擬事件在句法上被允許嗎? – 2010-10-15 06:34:53

+1

@John。關於---「請注意,您的事件簽名與事件的常規約定不符 - 任何不使用EventHandler的原因?」我只是利用現有的「Action」委託,因爲在這種情況下,我不需要任何參數(object,eventargs)在這個事件的訂閱者中。這(再次)是一種糟糕的編程習慣嗎?爲這種情況創建一個單獨的(空)代表是否更好? – 2010-10-15 06:41:37

+1

@Thomas:有些方法可以*合理地使用它們 - 例如,您可以記錄每個訂閱,然後將其傳遞給基本實現。此外,您還需要能夠有效地抽象事件以將其置於接口中。 – 2010-10-15 06:57:10