2010-08-17 42 views
9

我正在使用C#3.0。遵循這一標準的事件模式,我有:我的班級是否應該訂閱自己的公共活動?

public event EventHandler<EventArgs> SomeEventHappens; 

    protected virtual void OnSomeEventHappens(EventArgs e) 
    { 
     if (SomeEventHappens != null) 
     { 
      SomeEventHappens(this, e); 
     } 
    } 

    private object _someProperty; 

    public object SomeProperty 
    { 
     get 
     { 
      return _someProperty; 
     } 
     private set 
     { 
      if (_someProperty == value) 
      { 
       return; 
      } 
      OnSomeEventHappens(EventArgs.Empty); 
      _someProperty = value; 
     } 
    } 

在我的同班我想的時候採取一些行動SomeProperty變化。我看到它的方式,我有3個替代品:

1)做我的SomeProperty二傳手。有些事情是因爲我試圖訂閱每件事物的哲學應該做一件事而做得很好,所以我錯了。把東西塞進一個二傳手似乎是違背了這一點,或者至少有傾向於。

2)在OnSomeEventHappens做東西。再次,似乎有點反對保持這個簡單的作品。此外,如果此方法被覆蓋,如果實現者不調用基方法,可能會失去功能。

3)是否訂購了SomeEventHappens。對我來說,就封裝而言,這似乎是一個合適的選擇,而且看起來很乾淨。再次,如果OnSomeEventHappens被覆蓋,可能會產生影響。

也許有更優雅的東西?我無法在方案2和方案3之間做出決定,而且我很好奇最佳實踐是什麼。畢竟,最安全的地方也許就是財產創造者。

想法?

更新: 感謝您的好評和下面的答案。我已經瞭解到,讓班級訂閱自己的活動是「可以的」,儘管在我的情況下,我傾向於因爲開銷而不願意這樣做。我已經考慮到了我的虛擬方法的潛在覆蓋者的行爲,以及我想要發生的事情。

在我的現實世界中,我並不想在未設置屬性的情況下引發事件。由於下面的答案指導了我的思考過程,所以我認爲我可以選擇1,因爲開銷較低,從繼承者那裏行爲不當的風險降低,並且通常對我來說更合適。再次感謝!

回答

2

如果您從某些常見位置(屬性過程或其他函數)調用SomeEventHappens和OnSomeEventHappens,那麼您不必擔心忽略引發事件的重寫器。我寧願重寫一個函數,而不是處理事件,因爲它的開銷較小。

+0

我選擇了這個答案,因爲它是我最終做的最接近的解釋。我從其他答案中學到了很多東西。謝謝! – 2010-08-18 12:01:29

1

你會總是想採取這個動作,或者你想要訂閱和取消訂閱?在後一種情況下,選項3顯然是一個好主意。

您希望採取的行動種類另一個班級可能希望採取的行動?再次,這將傾向於選項3.

您希望採取的行動固有地設置屬性的一部分?如果是這樣,那麼行動1可能是明智的。

選項3聽起來像一個很好的「輕觸」方法給我。

+0

在我的真實世界的情況(而不是簡單的版本以上),我不想訂閱和取消訂閱。該屬性實際上是一個枚舉,並根據所設置的枚舉值引發大量不同事件中的任何一個。由於我正在籌備賽中提升賽事,因此我可以在那裏獲得所有賽事信息。從頭腦的角度來看,不要訂閱所有這些事件,只需要在二傳手中處理它就可能更輕。 – 2010-08-17 19:30:54

2

在.NET以外的對象框架中,訂閱自己事件的對象主要是因爲這樣的事情導致循環引用可能使對象無限期地活動而不被接受。這不是一個問題。NET,但對於我來說,對於一個物體以這種方式摸索它仍然是「奇怪的」。

如果一個類總是需要知道屬性發生了什麼變化,那麼最好的辦法就是使OnSomeEventHappens方法變爲虛擬,並在需要額外信息的後代類中覆蓋它。在事件觸發方法中放置代碼是可以的。事件觸發的方法正是在這種情況下,每個想要觸發該事件的人都有統一的方法來執行此事。

如果您只是偶爾需要了解屬性更改的時間,那麼我認爲訂閱和取消訂閱該事件是適當的。

+0

我最初的想法是,它可能會被一個班級自訂。從其他一些答案和你的答案來看,它似乎不是.NET中的問題。如果我在我的OnSomeEventHappens虛擬方法中添加了一些額外的邏輯,我需要採取信念的飛躍,即覆蓋者將在其覆蓋中調用基礎版本。對於我的目的,我仍在辯論這是否會成爲問題。 – 2010-08-17 19:12:34

+1

虛擬和事件之間的主要區別在於事件應該是/應該是無約束的,對於事件處理程序應該做什麼有很少或沒有要求,而虛擬本質上是契約式的。應該記錄虛擬方法來描述何時以及是否應該在擴展或覆蓋行爲時被後代稱爲虛擬方法。 IOW,如果你的覆蓋者是優秀的程序員,這不應該成爲一個主要問題。如果你的覆蓋者是普通公衆/隨機白癡,那麼可能需要防禦工事。 – dthorpe 2010-08-17 19:22:25

+0

任何覆蓋都有可能成爲我未來的自我的99%的機會,無論是我把它帶入優秀程序員的類別還是隨機白癡的爭論! :) – 2010-08-17 19:34:50

1

如果您擁有自己的對象的狀態,捕捉事件對我來說聽起來是錯誤的。我會用一個單獨的虛擬方法去。不要干涉你的活動,並希望孩子們扔它。也許這看起來像這樣:

private object _someProperty; 
    public object SomeProperty 
    { 
     get 
     { 
      return _someProperty; 
     } 
     private set 
     { 
      if (_someProperty != value) 
      { 
       OnSettingSomeProperty(_someProperty, value); 
       OnSomeEventHappens(EventArgs.Empty); 
       _someProperty = value; 
      } 
     } 
    } 

    protected virtual void OnSettingSomeProperty(object oldValue, object newValue) 
    { 
     // children can play here, validate and throw, etc. 
    } 
+0

這可以追溯到選項1.雖然我不認爲我會使OnSettingSomeProperty虛擬,可能是私人的,所以我可以保證它不會被錯過。我並不關心事件的發生,而是首先提出的事件。 – 2010-08-17 19:57:47

+0

@jomtois,OnSettingSomeProperty的意圖是允許後代注入行爲。很明顯,你有什麼,但不是你原來的帖子中的內容。也許你對任何人的回答都不滿意,因爲你沒有在你的問題中定義「做什麼......」。 – Marc 2010-08-17 21:06:21