2010-05-14 40 views
1

如果我有一個引發事件的類,使用(例如)FrobbingEventArgs,我可以用一個接受EventArgs的方法來處理它嗎?在C#中,是否事件處理函數參數是逆變?

下面是一些代碼:

class Program 
{ 
    static void Main(string[] args) 
    { 
     Frobber frobber = new Frobber(); 
     frobber.Frobbing += FrobberOnFrobbing; 
     frobber.Frob(); 
    } 

    private static void FrobberOnFrobbing(object sender, 
     EventArgs e) 
    { 
     // Do something interesting. Note that the parameter is 'EventArgs'. 
    } 
} 

internal class Frobber 
{ 
    public event EventHandler<FrobbingEventArgs> Frobbing; 
    public event EventHandler<FrobbedEventArgs> Frobbed; 

    public void Frob() 
    { 
     OnFrobbing(); 

     // Frob. 

     OnFrobbed(); 
    } 

    private void OnFrobbing() 
    { 
     var handler = Frobbing; 
     if (handler != null) 
     handler(this, new FrobbingEventArgs()); 
    } 

    private void OnFrobbed() 
    { 
     var handler = Frobbed; 
     if (handler != null) 
     handler(this, new FrobbedEventArgs()); 
    } 
} 

internal class FrobbedEventArgs : EventArgs { } 
internal class FrobbingEventArgs : EventArgs { } 

我想問的原因是,ReSharper的,似乎有一個問題(什麼樣子)等效於XAML,我想知道,如果它是一個錯誤的ReSharper的,或者我對C#的理解錯誤。

+1

這是frobnication的一個很好的例子:) – 2010-05-14 10:49:46

回答

6

也許協變的不是字

關閉。您正在尋找的詞是contravariant。方法組到代表類型的轉換爲協變式返回類型和逆變換正式參數類型。

下面是關於這個問題我的博客文章:

http://blogs.msdn.com/ericlippert/archive/2007/10/19/covariance-and-contravariance-in-c-part-three-member-group-conversion-variance.aspx

,如果我有一個類,引發一個事件,與(例如)FrobbingEventArgs,我是允許使用,需要一個方法來處理它EventArgs的?

那麼,你試過它,它的工作,很明顯是的。有關說明中的理由,請參閱有用的標題爲「方法組轉換」的部分。

+0

埃裏克,感謝您的更正 - 將「協變」改爲「逆變」。也感謝您的理由。 – 2010-05-14 15:11:45

+0

這是沒有問題的,並且正常工作,因爲'Main'中的第二個代碼行的方法組轉換轉換爲完全相同的構造泛型類型。 (運行時類型等於編譯時類型。)所以這也適用於.NET 2.0。如果有人來這裏搜索_「反變化」_,請注意以下內容(.NET 4.0):不要像'公共事件動作 Frobbing;'這樣的事件'因爲'動作'是逆變的('in' )。然後人們可以添加一個「動作」或類似的事件。如果其他用戶使用不同的「動作」,那**將不會工作。 – 2012-11-12 14:32:45

1

是的你可以,但是當你在事件處理程序中訪問e參數時,除非將它作爲派生類型轉換,否則只能訪問屬於EventArgs基類的成員。我認爲這個詞是多態的,而不是協變的,而且c#中的所有類都是pollymorphic,它是一種語言特徵。

+0

是FrobbedEventArgs可強制轉換爲EventArgs的事實是多態的,但我認爲事實是EventHandler類型的委託可以被添加到事件處理程序事件是協方差。 – Niki 2010-05-14 11:11:38

+0

@nikie其實,如果你[看看EventHandler '](http://msdn.microsoft.com/en-us/library/db0etb8x.aspx),你會發現它是**不變**,不是逆變,在它的通用參數中。它說'EventHandler ',而不是'EventHandler <在TEventArgs>'中。所以在這種情況下,就像你所說的那樣,不可能將一個EventHandler '添加到EventHandler 事件中。因此,即使靜態目標方法對其參數具有「更小」的要求,它也是創建「EventHandler 」的方法組轉換的逆轉。 – 2012-11-12 15:16:18

+0

@JeppeStigNielsen:你注意到的行爲是微軟決定不讓代表定義一個'Combine'方法,而是使用'Delegate.Combine'的一個不幸後果。給定接口IFoo,IBar和IBoth:IFoo,IBar,如果委託類型「動作」定義了它自己的組合方法,則可能「動作。康寧」接受「動作」和「動作」併產生一個「動作」。但是,實際上,Delegate.Combine沒有辦法確定它可能使用什麼類型來組合'Action '和'Action '。 – supercat 2012-12-08 00:05:02

-1

由於事件只能在聲明它們的類中進行調用,因此派生類不能直接調用在基類中聲明的事件。

您可以通過爲事件創建受保護的調用方法來實現您想要的功能。通過調用這個調用方法,您的派生類可以調用該事件。

爲了獲得更大的靈活性,調用方法通常被聲明爲虛擬的,這允許派生類覆蓋它。這允許派生類攔截基類正在調用的事件,可能會自己處理它們。

你可以這樣做:

protected void OnFrobbing(EventArgs e) 
    { 
     var handler = Frobbing; 
     if (handler != null) 
     handler(this, new e); 
    } 

或者:

protected virtual void OnFrobbing(EventArgs e) 
    { 
     var handler = Frobbing; 
     if (handler != null) 
     handler(this, new e); 
    } 
+0

-1:這是EventArgs的派生,而不是提高事件的類... – 2010-05-14 12:31:53

相關問題