イベントは本当に素晴らしいです、そして私はそれらなしで私が何をするかわかりませんが、それらは私にとって謎です。
ある意味でイベントについて話しているのですが、プロパティまたは値である特別なイベントが発生した場合に関数が呼び出されます。
私はこれらが実際にどのように機能するかについて最も漠然とした考えしか持っていません。私はそれがオブザーバーパターンであることを知っていますが、それがどのように機能するか、および/またはそれを実装する方法を本当に知りません。
誰かが私にそれを説明できますか?
イベントは本当に素晴らしいです、そして私はそれらなしで私が何をするかわかりませんが、それらは私にとって謎です。
ある意味でイベントについて話しているのですが、プロパティまたは値である特別なイベントが発生した場合に関数が呼び出されます。
私はこれらが実際にどのように機能するかについて最も漠然とした考えしか持っていません。私はそれがオブザーバーパターンであることを知っていますが、それがどのように機能するか、および/またはそれを実装する方法を本当に知りません。
誰かが私にそれを説明できますか?
私が理解しているように、あなたはイベントが隠れてどのように機能するかを尋ねています。あなたはあなたが尋ねている言語/プラットフォームを指定していないので、私が知っていること(.Net)で答えるつもりですが、多くのプラットフォームは似ていると確信していますが、私が言うことはそうではないかもしれないことを覚えておいてくださいどこでも真実。
一番下のレベルから始めて、上に向かっていきます。
関数ポインタ
ほとんどの言語には、関数ポインタの概念があります。C ++のような言語では、メソッドのメモリアドレスへのポインタを文字通り格納できます。LispやF#のような関数型言語では、関数が重要であり、関数参照を格納して渡すことができる言語の重要な部分です。.netでは、関数ポインターはデリゲートを使用して実装されます。
代表者
.Netでは、イベントはデリゲートを使用して実装されます。デリゲートは、タイプセーフな関数ポインタです。これは、特定の型に制限され、コンパイル時にその型に対してチェックされる関数へのポインターです。デリゲートをトリガーすると、それが指す関数が呼び出されます。
マルチキャスト
マルチキャストデリゲートは、デリゲートのコレクションを形成するクラスです。内部でリストを使用して、複数のデリゲートを格納します。電話をかけるとき、add
または電話をかけるとき+=
は、新しいデリゲート(関数ポインタ)をマルチキャストの内部リストに追加するだけです。マルチキャストデリゲートインスタンスはトリガーでき、リストを下に移動して、各デリゲートを順番に内部でトリガーします。
イベント
イベントは、イベントを支えるマルチキャストデリゲートにいくつかの追加の制限を追加する単なるキーワードです。たとえば、(とりわけ)マルチキャストデリゲートインスタンスを宣言するときにeventキーワードを使用すると、宣言されたクラス内からのみトリガーできるように制限されます。
つまり、要約すると。イベントは関数ポインタの単なるリストです。サブスクライブするときは、関数へのポインターをリストに追加するだけです。イベントがトリガーされると、リストを下に移動し、認識している各関数ポインターをトリガーします。
明らかに、最初に言ったように、すべての言語/環境は異なりますが、関数ポインターの単純なリストを維持するという考えがおそらくかなり一般的であるとしても、私は驚かないでしょう。
Jon Skeetには、 .Netのイベントに関する優れた記事があり、これが関心のあるプラットフォームである場合は、詳細を読む必要があります。
イベントは、実際には高レベルで非常に単純です。
まず、オブジェクトは、他のオブジェクトがサブスクライブできるイベントを定義します。オブジェクトがイベントに登録すると、オブジェクトは、イベントが発生したときに呼び出される関数参照(またはデリゲート)を格納します。
次に、関心のあるオブジェクトは、関数参照をObservableオブジェクトに渡すことによってイベントをサブスクライブします(関数は、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
}
}
オブザーバーへのインターフェース(必ずしもjava / c#などのインターフェースキーワードの意味ではありません)が必要です。オブザーバーに通知する必要があるときに呼び出すメソッドを何らかの方法で知る必要があります。オブザーバーは彼らの興味を登録し、あなたはそれらをリストに追加します。
通知するものを受け取るたびに、オブザーバーのリストを調べて、それぞれのメソッドを呼び出します。誰かがこれ以上通知を受けたくない場合は、オブザーバーのリストからそれらを削除するだけです。
組み込みの「イベント」またはc#のデリゲートを使用しないac#の例を次に示します。
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();
}
}
}