2011-06-07 49 views
4

有什麼區別?通過代表和事件調用的區別C#

使用委託

public delegate void TestDelegate(); 
public TestDelegate delObj = SomeMethod; 

public void SomeMethod() 
{ 
    ..... 
} 

public void Test() 
{ 
    if(delObj != null) 
     delObj(); 
} 

使用事件

public delegate void TestDelegate(); 
public event TestDelegate EdelObj += SomeMethod; 

public void SomeMethod() 
{ 
    ..... 
} 

public void Test() 
{ 
    if(EdelObj != null) 
     EdelObj(); 
} 

似乎都工作。任何人都可以解釋什麼是不同的,我們應該使用上面的哪一種?

編輯 鏈接適用於兩者。對不起,這是我的錯誤。

感謝 NISHANT

+0

鏈接作品也是如此。 – 2011-06-07 15:37:10

回答

2

事件聲明實際上只是一種用於公開委託的特殊屬性。但是,它不是獲取和設置訪問器,而是創建添加和刪除訪問器。通常它們會自動執行,但如果您希望可以添加自定義行爲:

private MyEventHandler handler; 
public event MyEventHandler MyEvent { 
    add { 
     handler += value; 
     Trace.WriteLine("MyEvent handler attached."); 
    } 
    remove { 
     handler -= value; 
     Trace.WriteLine("MyEvent handler removed."); 
    } 
} 

這樣做有兩件事。首先,因爲事件是屬性,所以它們可以包含在接口中。其次,由於MyEvent不返回值,委託被完全封裝,只有擁有它的對象可以調用它。其他暴露委託的方式會產生一個可以被任何人調用的委託。

除了特殊語言支持之外,事件和代表之間的另一個主要區別是約定而不是語言或框架功能:事件預計將遵循certain patterns,例如確保事件發生的代理基於EventHandler代表建立的模式。

通常,只要語義是通知任何對其舞臺上的變化感興趣的對象的語義,則事件就是優選的。在希望其他人能夠通過提供自己的過程來定義行爲的情況下,首選委託人,例如LINQ中使用的許多IEnumerable擴展方法所採用的委託參數。

+0

謝謝。我覺得我到了那裏。但在我心中仍然有一些疑慮。我只是嘗試從另一個班級調用一個活動,但它不像代表那樣。所以這是一個區別。但是我無法理解你給出的支持這種行爲的陳述「,因爲MyEvent沒有返回值,委託被完全封裝並且只有擁有它的對象才能調用它」。你可以多給它點一下嗎? – Nishant 2011-06-08 05:20:30

+1

它的工作方式是因爲'add'和'remove'訪問器在一個事件中更像是一個屬性中的'set'訪問器:它們接受一個參數('value')並使用它來修改事件涵蓋,並且只能在事件或財產是賦值語句的目標時才能使用。在事件中沒有與「獲取」訪問器等價的內容,因此無法評估事件以獲取支持它的代理。由於您無法通過事件獲取委託,因此無法通過事件調用委託。 – 2011-06-08 15:49:15

+0

非常感謝你肖恩!現在都清楚了。 – Nishant 2011-06-08 18:26:29

1

它不是委託VS事件,事件是一種-周圍的委託財產。

一般來說,你應該總是使用第二種方案,因爲在第一個public TestDelegate delObj是一個公共字段,打破封裝。

您可以在類的接口中使用事件,並將其作爲參數委託給方法。

2

它的工作原理完全相同。如果您使用

public event EventHandler SomeEvent; 

的C#編譯器(簡化代碼):當您使用SomeEvent += ...remove_SomeEvent被稱爲當您使用SomeEvent -= ...

private EventHandler SomeEventField; 
public void add_SomeEvent(EventHandler handler) { 
    this.SomeEventField = (EventHandler)Delegate.Combine(this.SomeEvent, handler); 
} 
public void remove_SomeEvent(EventHandler) { 
    this.SomeEventField = (EventHandler)Delegate.Remove(this.SomeEvent, handler); 
} 

方法add_SomeEvent被調用。

但是在這兩種情況下都使用相同的代表。

+2

默認事件add/remove訪問器也會鎖定'this'以在更新基礎代理時提供線程安全性。這不是一個很好的做法(因爲'this'是公開可見的),但它被C#設計人員選擇爲合理的折中方案,以防止在使用事件時出現常見的「疑難雜症」。事件以這種方式包裝的另一個副作用是外部類無法檢索或調用基礎代理;只有定義事件的類可以調用事件的委託。 – 2011-06-07 15:50:47

+0

@丹·布萊恩特:謝謝你的提示。爲了簡單起見,我滑過鎖定。正如我寫的 - 它是「簡化代碼」。 – TcKs 2011-06-07 15:53:45

+2

@TcLs,理解;我只是覺得值得一提,因爲這是一個非常重要的實現細節,可能會產生意想不到的後果(例如,它可能被用來創建令人困惑的死鎖)。 – 2011-06-07 15:58:08

1

它實際上是事件的一個屬性包裝。

主要區別在於您無法從類外調用/引發事件,而您可以調用公共代理。

鏈接(+ =)對代表和事件來說沒有什麼不同。

0

C#有許多構造不會添加任何新的語言,但它們只是構造函數的語法糖,因爲構造需要某種形式的代碼,這種代碼每次都會一遍又一遍地輸入。例如using語句與調用dispose方法的try-finally塊相當,屬性只是get和/或set方法的語法糖。

以類似的方式,事件只是代表字段的語法糖。然而,其他人已經提到了一些細微的差異。由於不建議使用公共領域,因此必須將代表封裝起來,這樣做的好方法就是使用事件。而且(正如馬克所說)這個事件只能從課堂內部調用。

我通常根據我在概念上認爲該字段或事件應該表示的內容,在委託字段和事件之間進行選擇。如果它代表任何人想要通知的事情,我會推薦該事件。否則,如果它表示例如獲取結果的函數,我會使用委託字段。

+0

事件對於委託字段而言不是語法糖。它們是'AddEventHandler()'和'RemoveEventHandler()'方法的語法糖。 – 2011-06-07 19:10:30