2010-04-21 7 views
0

이벤트는 정말 멋지고, 나는 그들없이 무엇을 할 것인지 모르겠지만, 그들은 나에게 수수께끼입니다.객체 이벤트, 어떻게 구현합니까?

나는 어떤 의미에서 이벤트에 대해 말하고 있는데, 속성 (값), 특수 이벤트가 발생하면 함수가 호출됩니다.

나는 이것이 실제로 어떻게 작동하는지 모호하게 생각합니다. 나는 이것이 관찰자의 패턴이라는 것을 알고 있지만 그것이 어떻게 작동하는지 그리고 어떻게 구현 하는지를 진정으로 알지 못한다.

누군가 나에게 설명 할 수 있습니까?

+2

어떤 언어에있는 경우 더 많은 정보를 읽어야 훌륭한 article on events in .Net이있다? – bmargulies

+1

정말 중요하지 않습니다. – Malfist

답변

2

나는 이벤트가 내부적으로 어떻게 작동하는지 당신이 요구하고 그것을 이해로서 :

다음은이 C#에서 '이벤트'또는 대표 내장 사용하지 않고 C# 예제입니다. 어떤 언어/플랫폼을 지정하지 않았으므로 내가 알고있는 것 (.Net)으로 답할 것입니다. 물론 많은 플랫폼이 비슷하다고 생각합니다. 사실 어디서나.

최저 수준에서 시작하여 위쪽으로 작업하겠습니다.

기능 포인터 대부분의 언어에서

함수 포인터의 개념이있다. C++과 같은 언어에서는 문자 그대로 메서드의 메모리 주소에 대한 포인터를 저장할 수 있습니다. Lisp이나 F # 함수 같은 함수형 언어가 핵심적이고 함수 참조를 저장하고 전달할 수있는 언어의 중요한 부분입니다. .net에서 함수 포인터는 델리게이트를 사용하여 구현됩니다.

대표는 닷넷 이벤트에서

는 위임을 사용하여 구현된다. delegate은 형식 안전 함수 포인터입니다. 함수에 대한 포인터입니다. 특정 유형으로 제한되며 컴파일 타임에 해당 유형에 대해 검사됩니다. 델리게이트를 트리거 할 수 있고 그것이 가리키는 함수를 호출 할 것입니다. 멀티 캐스트

multicast delegate

는 델리게이트의 컬렉션을 형성하는 클래스이다. 내부적으로 목록을 사용하여 여러 대리자를 저장합니다. add을 호출하거나 +=을 호출하면 멀티 캐스트의 내부 목록에 새 대리자 (함수 포인터)를 추가하기 만하면됩니다. 멀티 캐스트 대리자 인스턴스가 트리거 될 수 있으며 목록을 아래로 이동하고 각 대리자를 차례대로 내부적으로 트리거합니다.

event

이벤트는 이벤트를 뒷받침 멀티 캐스트 대표의 상단에 몇 가지 추가 제한을 추가하는 키워드입니다. 예를 들어 멀티 캐스트 대리자 인스턴스를 선언 할 때 event 키워드를 사용하여 선언 된 클래스 내에서만 트리거 될 수 있도록 이벤트 키워드를 사용합니다 (

). 이벤트는 함수 포인터의 목록 일뿐입니다. 구독 할 때 간단히 함수에 대한 포인터를 목록에 추가하십시오. 이벤트가 트리거되면 목록을 아래로 이동하고 알 수있는 각 함수 포인터를 트리거합니다.

분명히 말했듯이 모든 언어/환경은 다를 것이지만 단순한 함수 포인터 목록을 유지하는 아이디어가 상당히 일반적이라면 놀랄 일이 아닙니다.

존 소총이 당신이 관심있는 플랫폼입니다.

0

이벤트가 실제로 높은 수준에서 매우 간단 제공합니다.

먼저, 객체는 다른 객체가 구독 할 수있는 이벤트를 정의합니다. 객체가 이벤트를 등록하면 객체는 이벤트가 발생할 때 호출 될 함수 참조 (또는 위임)를 저장합니다.

다음으로 관심있는 Object는 Observable Object에 함수 참조를 전달하여 이벤트에 구독합니다 (이 함수는 Observable 클래스에서 제공하는 서명과 일치해야 함).

이벤트가 발생하면 Observable 클래스가 적절한 메서드를 호출합니다. 여기

는 (C#으로) 빠른 예제 :

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 
    } 
} 
+0

좋아, 이제는 낮은 레벨 (흥미 롭다고 가정);) ... – FrustratedWithFormsDesigner

+1

@FrustratedWithFormsDesigner 재미 있어요 ...하지만 언어는 구현에 따라 다릅니다. 그것은 모두 원하는 세부 사항에 달려 있습니다. ;-) –

+0

당신은 C# 예제를 주 었으니 까, 그걸로 ... 지금 당장 (OS X이 Objective-C와 함께 사용했던 이벤트 모델이 다소 흥미 롭다는 것을 모호하게 상기했지만) – FrustratedWithFormsDesigner

0

당신은하지 굳이 용 (인터페이스가 필요 변경된 이벤트에 가입하고자하는 다른 클래스에서 다음

// 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()); 
    } 
} 

그리고 예를 들어 java/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(); 
    } 
} 
} 
관련 문제