[C#] 了解C#中的事件和事件處理程序


Answers

C#知道兩個術語, delegateevent 。 我們從第一個開始。

代表

delegate是對方法的參考。 就像您可以創建對實例的引用一樣:

MyClass instance = myFactory.GetInstance();

您可以使用委託來創建對方法的引用:

Action myMethod = myFactory.GetInstance;

現在您已經引用了一個方法,您可以通過引用調用該方法:

MyClass instance = myMethod();

但你為什麼? 你也可以直接調用myFactory.GetInstance() 。 在這種情況下,你可以。 但是,有很多情況需要考慮您不希望應用程序的其餘部分知道myFactory或直接調用myFactory.GetInstance()

一個明顯的myFactory.GetInstance()是,如果您希望能夠從一個中心位置(也稱為工廠方法模式 )將myFactory.GetInstance()替換為myOfflineFakeFactory.GetInstance() )。

工廠方法模式

所以,如果你有一個TheOtherClass類,並且它需要使用myFactory.GetInstance() ,這就是沒有委託的情況下代碼的樣子(你需要讓TheOtherClass知道你的myFactory的類型):

TheOtherClass toc;
//...
toc.SetFactory(myFactory);


class TheOtherClass
{
   public void SetFactory(MyFactory factory)
   {
      // set here
   }

}

如果您使用委託,您不必公開我的工廠的類型:

TheOtherClass toc;
//...
Action factoryMethod = myFactory.GetInstance;
toc.SetFactoryMethod(factoryMethod);


class TheOtherClass
{
   public void SetFactoryMethod(Action factoryMethod)
   {
      // set here
   }

}

因此,您可以委派其他一些班級使用,而不必將您的類型暴露給他們。 你唯一要公開的是你的方法的簽名(你有多少個參數等等)。

“我的方法簽名”,我以前從哪裡聽過? 哦,是的,接口! 接口描述整個類的簽名。 認為代表僅僅描述了一種方法的簽名!

接口和委託之間的另一個很大的區別是,當你編寫你的類時,你不必對C#說“這個方法實現了這種類型的委託”。 有了接口,你需要說“這個類實現了這種類型的接口”。

此外,委託引用可以(有一些限制,參見下文)引用多個方法(稱為MulticastDelegate )。 這意味著當您調用委託時,將執行多個顯式連接的方法。 對象引用始終只能引用一個對象。

MulticastDelegate的限制是(方法/委託)簽名不應該有任何返回值( void ),並且簽名中不使用關鍵字outref 。 顯然,你不能調用返回一個數字的兩個方法,並期望它們返回相同的數字。 一旦簽名符合,委託自動成為MulticastDelegate

事件

事件只是屬性(如get; set;屬性到實例字段),這些屬性向其他對象公開訂閱。 但是,這些屬性不支持get; set ;. 相反,他們支持添加;刪除;

所以你可以有:

    Action myField;

    public event Action MyProperty
    {
        add { myField += value; }
        remove { myField -= value; }
    }

UI中的用法(WinForms)

所以,現在我們知道委託是對方法的引用,並且我們可以有一個事件讓世界知道他們可以給我們的方法從我們的委託中引用,而我們是一個UI按鈕,那麼:我們可以詢問任何對我是否被點擊感興趣的人,向我們註冊他們的方法(通過我們公開的事件)。 我們可以使用所有提供給我們的方法,並由我們的代表引用它們。 然後,我們將等待,直到用戶來到並點擊該按鈕,然後我們將有足夠的理由調用委託。 而且由於委託引用了所有給予我們的方法,所有這些方法都會被調用。 我們不知道這些方法做了什麼,也不知道哪個類實現了這些方法。 我們所關心的只是有人對我們被點擊感興趣,並且給了我們一個符合我們想要的簽名的方法的參考。

Java的

像Java這樣的語言沒有代表。 他們改用接口。 他們這樣做的方式是詢問任何對'我們被點擊'感興趣的人來實現某個接口(使用我們可以調用的特定方法),然後給我們實現接口的整個實例。 我們可以保存實現此接口的所有對象的列表,並且可以在我們點擊時調用他們的'我們可以調用的某些方法'。

Question

我理解事件的目的,特別是在創建用戶界面的情況下。 我認為這是創建活動的原型:

public void EventName(object sender, EventArgs e);

事件處理程序做什麼,它們為什麼需要,以及如何創建一個?




我對事件的理解是;

代表:

一個變量來保存對要執行的方法/方法的引用。 這使得可以傳遞像變量這樣的方法。

創建和調用事件的步驟:

  1. 該事件是一個委託的實例

  2. 由於事件是委託的實例,因此我們必須首先定義委託。

  3. 分配事件觸發時要執行的方法/方法( 調用委託

  4. 啟動事件( 致電代表

例:

using System;

namespace test{
    class MyTestApp{
        //The Event Handler declaration
        public delegate void EventHandler();

        //The Event declaration
        public event EventHandler MyHandler;

        //The method to call
        public void Hello(){
            Console.WriteLine("Hello World of events!");
        }

        public static void Main(){
            MyTestApp TestApp = new MyTestApp();

            //Assign the method to be called when the event is fired
            TestApp.MyHandler = new EventHandler(TestApp.Hello);

            //Firing the event
            if (TestApp.MyHandler != null){
                TestApp.MyHandler();
            }
        }

    }   

}



這實際上是一個事件處理程序的聲明 - 一個將在事件被觸發時被調用的方法。 要創建一個事件,你會寫這樣的東西:

public class Foo
{
    public event EventHandler MyEvent;
}

然後你可以訂閱這樣的事件:

Foo foo = new Foo();
foo.MyEvent += new EventHandler(this.OnMyEvent);

用這樣的OnMyEvent()定義:

private void OnMyEvent(object sender, EventArgs e)
{
    MessageBox.Show("MyEvent fired!");
}

每當Foo關閉MyEvent ,您的OnMyEvent處理程序將被調用。

您並不總是必須使用EventArgs的實例作為第二個參數。 如果您想包含其他信息,則可以使用從EventArgs派生的類( EventArgs是按慣例的基礎)。 例如,如果您查看在WinForms中的Control中定義的一些事件或WPF中的FrameworkElement ,則可以查看向事件處理程序傳遞附加信息的事件示例。




//This delegate can be used to point to methods
//which return void and take a string.
public delegate void MyDelegate(string foo);

//This event can cause any method which conforms
//to MyEventHandler to be called.
public event MyDelegate MyEvent;

//Here is some code I want to be executed
//when SomethingHappened fires.
void MyEventHandler(string foo)
{
    //Do some stuff
}

//I am creating a delegate (pointer) to HandleSomethingHappened
//and adding it to SomethingHappened's list of "Event Handlers".
myObj.MyEvent += new MyDelegate (MyEventHandler);





Links