簡體   English   中英

為什么我們不能用訪問器引發事件?

[英]Why can´t we raise event with accessors?

為什么我們不能用自定義實現來引發事件,而沒有它們卻是可能的? 看到這個代碼:

public class Program
{
    private EventHandler myEvent;
    public event EventHandler MyEvent
    {
        add { myEvent += value; }
        remove { myEvent -= value; }
    }

    public event EventHandler AnotherEvent;

    public static void Main()
    {
        var target = new Program();
        target.MyEvent(null, null);       // ERROR CS0079
        target.AnotherEvent(null, null);  // compiles
    }
}

您會看到這兩個事件都在我的班級中聲明。 雖然target.AnotherEvent(...)編譯得很好,但target.MyEvent(...)不會:

Event MyEvent 只能出現在 += 或 -= 的左側。

我知道一個事件只是一個帶有添加和刪除方法的委托。 因此, AnotherEvent被編譯器轉換為 add- 和 remove-method:

private EventHandler _AnotherEvent;
public event EventHandler AnotherEvent
{ 
    add { _AnotherEvent += value; }
    remove { _AnotherEvent -= value; }
}

所以我假設對AnotherEvent的調用被編譯器替換為對私有委托的調用,即_AnotherEvent(...)

我做對了嗎? 有沒有關於為什么第二個調用有效而前者無效的文檔? 或者至少有關於編譯器在這里做什么的任何描述?

使用自動事件時public event EventHandler AnotherEvent; . 編譯器將為它創建一個字段(和一些方法),並在該字段上完成調用。 所以public event不再存在。 這是語法糖。

因此調用非自動事件是不可能的。 因為在編譯的代碼中找不到它。 它被add_remove_方法取代。 您只能在私有字段(生成的)上調用

這解釋了為什么不能在類實例之外調用事件。

它不起作用,因為現在有簡單的方法來獲取實際的可調用事件處理程序。 正如您所指出的,只有addremove ,而不是get

事件處理程序生成的代碼是:

.event [mscorlib]System.EventHandler MyEvent
{
  .addon instance void ConsoleApp1.Program::add_MyEvent(class [mscorlib]System.EventHandler)
  .removeon instance void ConsoleApp1.Program::remove_MyEvent(class [mscorlib]System.EventHandler)
} // end of event Program::MyEvent

它添加了兩個方法引用,一個用於add ,一個用於remove 如果你看它,它怎么知道調用什么方法? 如果addremove比現在復雜得多怎么辦? 只是無法確定要調用哪個事件處理程序。

這是語法糖。 您可以像支持字段一樣調用AnotherEvent是編譯器提供的便利( AnotherEvent是所謂的類似字段的事件)。 一旦你添加了你自己的訪問器,事件聲明就不再是一個類似字段的事件,必須通過它的支持字段來調用。

請參閱C# 語言規范的相關部分:

類場事件

在包含事件聲明的類或結構的程序文本中,某些事件可以像字段一樣使用。 要以這種方式使用,事件不能是抽象的或外部的,並且不能顯式包含 event_accessor_declarations。 此類事件可用於允許字段的任何上下文中。 該字段包含一個委托(Delegates),它指的是已添加到事件中的事件處理程序列表。 如果未添加任何事件處理程序,則該字段包含 null。

(強調我的)

建議您在添加或刪除新的事件處理程序方法之前鎖定事件。

說到這里,看看這段代碼:

public event EventHandler MyEvent
{
    add
    {
        lock (objectLock)
        {
            myEvent += value;
        }
    }
    remove
    {
        lock (objectLock)
        {
            myEvent -= value;
        }
    }
}

原因public event EventHandler AnotherEvent; 有效是因為當您的代碼中沒有提供自定義事件訪問器時,編譯器會自動添加它們。

遵循此文檔, 如何:實現自定義事件訪問器以獲得有關正確實現的更多詳細信息以及其他來源的這篇文章

關於實施:

 private EventHandler myEvent;
 public event EventHandler MyEvent
    {
        add
        {
            lock (objectLock)
            {
                myEvent += value;
            }
        }
        remove
        {
            lock (objectLock)
            {
                myEvent -= value;
            }
        }
    }

    public event EventHandler AnotherEvent;

    public static void Main()
    {
        var target = new Program();
        var myEvent =  target.MyEvent;
        myEvent?.Invoke(EventArgs.Empty, EventArgs.Empty);      
        target.AnotherEvent(null, null); 
    }

編輯以解釋實現:

var myEvent =  target.MyEvent;

對於顯式事件,您必須提供自己的后備存儲 - 委托字段或EventHandlerList東西,所以我們在這里只使用var

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM