事件真的很棒,如果沒有它們,我不知道我會做什麼,但它們對我來說是個謎。對象事件,它們是如何實現的
我說的是某種意義上的事件,如果一個屬性或值,一個特殊事件發生,就會調用一個或多個函數。
我只有這些實際工作方式的想法。我知道這是一個觀察者模式,但我並不真正知道它是如何工作的和/或如何實現它。
有人可以向我解釋嗎?
事件真的很棒,如果沒有它們,我不知道我會做什麼,但它們對我來說是個謎。對象事件,它們是如何實現的
我說的是某種意義上的事件,如果一個屬性或值,一個特殊事件發生,就會調用一個或多個函數。
我只有這些實際工作方式的想法。我知道這是一個觀察者模式,但我並不真正知道它是如何工作的和/或如何實現它。
有人可以向我解釋嗎?
據我所知,你問事件的幕後是如何工作的。你還沒有指定你問的是哪種語言/平臺,所以我會用我所知道的(.Net)來回答,儘管我相信很多平臺都是類似的,牢記我說的可能不是無處不在。
我會從最低層開始向上工作。
函數指針
在大多數語言中有一個函數指針的概念。在像C++這樣的語言中,你可以從字面上存儲一個指向方法內存地址的指針。在像Lisp或F#這樣的函數式語言中,函數是關鍵,它是語言的關鍵部分,您可以存儲和傳遞函數引用。在.net中,函數指針是使用委託來實現的。
代表
.NET中的事件是使用委託來實現。 A delegate是一個類型安全的函數指針。它是一個指向函數的指針,僅限於特定類型,並在編譯時針對該類型進行檢查。您可以觸發委託並調用它指向的功能。
組播
一個multicast delegate是形成代表的集合類。它在內部使用一個列表來存儲多個代表。當您撥打add
或撥打+=
時,您只需將新的委託(功能指針)添加到組播的內部列表中即可。多播委託實例可以被觸發,並且它簡單地向下移動列表並在內部觸發每個委託。
事件
的event僅僅是對鞏固該事件的多播委託的頂部增加了一些額外的限制關鍵字。例如(除別的以外),當你聲明多播委託實例時,通過使用event關鍵字來限制它,以便它只能從它聲明的類中觸發。
所以,總結一下。事件只是一個函數指針列表。當你訂閱你簡單的添加一個指向你的函數的指針到列表。當事件被觸發時,它簡單地向下移動列表並觸發它所知道的每個函數指針。顯然,就像我在開始時所說的,每種語言/環境都會有所不同,但如果維護一個簡單的函數指針列表的想法可能相當普遍,我不會感到驚訝。
喬恩斯基特具有優良的article on events in .Net,你應該閱讀的詳細信息,如果是這樣的平臺,你有感興趣的
活動實際上是在較高的水平很簡單。
首先,一個對象定義了一個其他對象可以訂閱的事件。當對象註冊一個事件時,對象存儲一個函數引用(或委託),當事件發生時將被調用。
接下來,感興趣的Object通過向Observable Object傳遞函數引用(該函數必須與Observable類提供的簽名匹配)來訂閱該事件。
當事件發生時,Observable類調用適當的方法。
下面是一個簡單的例子(在C#):
// Specifies the signature for the event and stores the reference
public delegate void ChangedEventHandler(object sender, EventArgs e);
public class ObservableObject
{
// Creates an event called Changed using the signature provided by the
// delegate.
public event ChangedEventHandler Changed;
// This is the method we're interested in notifying subscribers about.
public void SomeInterestnigMethod()
{
// Something just changed, notify subscribers
Changed(this, new EventArgs());
}
}
然後在想要訂閱Changed事件的另一個類:
public class Observer
{
ObservableObject _obj = new ObservableObject();
public Observer()
{
// Pass the function reference to objChangedHandler to the
// Observable Object.
_obj.Changed += objChangedHandler;
}
public void objChangedHandler(object sender, EventArgs e)
{
// Handle the event here
}
}
好吧,現在低級別(假設它是有趣的);)... – FrustratedWithFormsDesigner 2010-04-21 18:22:20
@FrustratedWithFormsDesigner這很有趣...但語言在他們的實現不同。這一切都取決於你想要的細節。 ;-) – 2010-04-21 18:24:07
你給了一個C#的例子,所以讓我們堅持下去...現在(儘管我隱約記得OS X與Objective-C一起使用的事件模型也似乎有點有趣;)) – FrustratedWithFormsDesigner 2010-04-21 18:35:22
你需要一個接口(未neccesarily在界面關鍵字的感覺,例如java/c#)給你的觀察者 - 當你需要 來通知他們時,你需要以某種方式知道調用哪個方法。觀察員註冊他們的興趣,並將他們添加到列表中。
每當你有東西要通知時,你都要通過觀察者列表,然後在每個觀察者上調用一個方法。如果有人不想再收到通知,這只是將它們從觀察員列表中刪除的問題。
這裏是不使用內置的「事件」或代表在C#中的C#示例:
using System;
using System.Collections.Generic;
namespace ObserverTest
{
interface IInvestor
{
void Update(Stock stock);
}
abstract class Stock
{
private string _symbol;
private double _price;
private List<IInvestor> _investors = new List<IInvestor>();
// Constructor
public Stock(string symbol, double price)
{
this._symbol = symbol;
this._price = price;
}
public void Attach(IInvestor investor)
{
_investors.Add(investor);
}
public void Detach(IInvestor investor)
{
_investors.Remove(investor);
}
public void Notify()
{
foreach (IInvestor investor in _investors)
{
investor.Update(this);
}
Console.WriteLine("");
}
public double Price
{
get { return _price; }
set
{
if (_price != value)
{
_price = value;
Notify();
}
}
}
public string Symbol
{
get { return _symbol; }
}
}
class IBM : Stock
{
public IBM(string symbol, double price)
: base(symbol, price)
{
}
}
class Investor : IInvestor
{
private string _name;
// Constructor
public Investor(string name)
{
this._name = name;
}
public void Update(Stock stock)
{
Console.WriteLine("Notified {0} of {1}'s " +
"change to {2:C}", _name, stock.Symbol, stock.Price);
}
}
class MainApp
{
static void Main()
{
IBM ibm = new IBM("IBM", 120.00);
ibm.Attach(new Investor("Sorros"));
ibm.Attach(new Investor("Berkshire"));
ibm.Price = 120.10;
ibm.Price = 121.00;
ibm.Price = 120.50;
ibm.Price = 120.75;
Console.ReadKey();
}
}
}
在什麼語言? – bmargulies 2010-04-21 18:25:32
並不重要。 – Malfist 2010-04-21 18:29:56