スポンサーサイト

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

F#入門初級編 第14回 Delegates と Events(2)

さて前回ですが、次のようなクラスを紹介しました。
type PublisherExamp () =
    let mutable _memoOfWhatToDo : list<PublisherExamp -> unit> = []
    member this.RememberWhatToDo (func) =
        _memoOfWhatToDo <- func :: _memoOfWhatToDo
    member private this.publishSomething () =
        for f in _memoOfWhatToDo do
            f this
    member this.SomethingHappen () =
        this.publishSomething ()            
 
次に、delegateが、関数をクラス化して、プラスアルファ(複数のdelegateを繋げて、一つのdelegate扱いできる等)を加えたものだと紹介しました。
ということは、能力的に
    let mutable _memoOfWhatToDo : list<PublisherExamp -> unit> = []
の代わりをdelegateが担当できるということです。
Eventというのは、クラスのプロパティにdelegateを割り当てるための、syntactic sugarです。
 
F#ではEvent<>型とEvent<,>型が準備されていますが、まずはEvent<,>型を紹介します。
これは次のように定義されています。
type Event<'Delegate,'Args (requires delegate)> =
 class
  new Event : unit -> Event<'Delegate,'Args>
  member this.Trigger : obj * 'Args -> unit
  member this.Publish :  IEvent<'Delegate,'Args>
 end
 
Triggerで「登録されたデリゲート」をInvokeします。この時の引数の型がobj*'Argsとなり、返り値がunit型です。objにはpublisher(=sender)が渡されます。
デリゲートの型はobj*'Args->unitとなります。
Publishの説明は後として'Argsをintとして簡単な例をつくってみます。
 
type myDel = delegate of obj*int-> unit
 
type myPublisher(i)= //一個のint型の値を保持するだけの簡単なクラス
    let _event1 =
        new Event<myDel,int>()
    member this.SomethingHappen()=
        _event1.Trigger(this,i) //引数は「このクラスのインスタンス」と「保持しておいた値」
 
    member this.Event1 = _event1.Publish       
 
最後の
    member this.Event1 = _event1.Publish       
の部分は、Publishプロパティを使って、外部からEvent1にdelegateを登録するための窓口を作っています。
_event.PublishはIEventインターフェイスを実装したオブジェクトの参照を渡します。
 
IEvent<,>インターフェイスは次のように定義されています。
 
type IEvent<'Delegate,'Args when 'Delegate : delegate<'Args,unit> and 'Delegate :> System.Delegate> =
 interface
  inherit IObservable<'Args>
  inherit IDelegateEvent<'Delegate>
 end
 
 
さらにIDelegateEventインターフェイスは次のように定義されています。
(IObservableについては後日紹介します。)
 
type IDelegateEvent<'Delegate> =
 interface
  abstract this.AddHandler : 'Delegate -> unit
  abstract this.RemoveHandler : 'Delegate -> unit
 end
 
AddHandlerメソッドにdelegateを渡して、delegateを登録することができます。
(取り除くのにはRemoveHandlerを使います。)
 
もう一度定義を再掲します。
 
type myDel = delegate of obj*int-> unit
 
type myPublisher(i)= //一個のint型の値を保持するだけの簡単なクラス
    let _event1 =
        new Event<myDel,int>()
    member this.SomethingHappen()=
        _event1.Trigger(this,i) //引数は「このクラスのインスタンス」と「保持しておいた値」
 
    member this.Event1 = _event1.Publish       
 
使ってみます。
 
> let t = myPublisher(7);; //7を保持するインスタンスの生成
val t : myPublisher
 
> t.Event1.AddHandler(myDel(fun sender args -> printfn "triggered %d" args)) ;;
//トリガーが引かれた時に実行するdelegateの登録
val it : unit = ()
 
> t.SomethingHappen();;//人為的にトリガーを引く
triggered 7
val it : unit = ()
 
さて.NetプログラミングはargとしてSystem.EventArgsを自分で派生させたクラスのインスタンスがよく使われます。(上の例ではintを渡していました。)
 
さてそれではSystem.EventArgsを自分で派生させたクラスを使用した例を挙げてみます。
 
まず時刻を記録できるように、System.EventArgsよりWhatTimeDidItHappenEventArgsクラスを派生させます。
 
type WhatTimeDidItHappenEventArgs (dateTime : System.DateTime) =
    inherit System.EventArgs()
    member this.DateTime = dateTime
 
次に、プールしておいて、Eventが発火したときに、実行されるdelegateの型を定義しておきます。
 
type DelegateForPublisherExampWithDelg = 
                    delegate of obj * WhatTimeDidItHappenEventArgs -> unit
 
それでは、publisherを定義します。
 
type PublisherExampWithDelg () =
    let _event1 = 
        new Event< DelegateForPublisherExampWithDelg,WhatTimeDidItHappenEventArgs>()
    member this.SomethingHappen() =
        _event1.Trigger(this,new WhatTimeDidItHappenEventArgs( System.DateTime.Now ))
    member this.Event1 = _event1.Publish
    
    member this.SomethingHappen() =
         _event1.Trigger(this,new WhatTimeDidItHappenEventArgs( System.DateTime.Now ))
の部分ですが、Triggerメソッドを使って、「eventが発火したとき、_event1にプールされたdelegateをTrigger以下のタプルに対して、invokeする」という処理を表しています。
(このタイミングで追加情報である、現在時間をインスタンス化しています。)
 
 
それでは使ってみましょう。
まずPublisherExampWithDelgのインスタンスを作成します。
 
>  let t = new PublisherExampWithDelg();;
val t : PublisherExampWithDelg
 
次にdelegateを作成します。
 
> let delExpamp1 = new DelegateForPublisherExampWithDelg(
                        fun sender args -> printfn "at %A  event fired" args.DateTime
                        );;
val delExpamp1 : DelegateForPublisherExampWithDelg
 
Eventがfireされたとき、追加情報に記録されている時間を表示するdelegateを作成しています。
 
つぎにAddHandlerメソッドをつかって、tにこのdelegateを登録します。
(Handlerというのは、日本語でいうと「捌き手」という感じでしょうか?なにかイベントが起こったときに、それを捌くというイメージです。)
 
> t.Event1.AddHandler(delExpamp1);;
 val it : unit = ()
 
それでは、外部から人為的にEventを発火してみます。
 
> t.SomethingHappen();;
at 2009/09/01 9:01:36  event fired
val it : unit = ()
 
(参考)次のようなdelegateを作成、追加することにより、Eventが発火されたとき、publisherの任意のメソッド等を実行させることができます。

let delExpamp2 = new DelegateForPublisherExampWithDelg(
                        fun sender args -> 
                            (sender :?> PublisherExamp).任意のメソッド
                        )
スポンサーサイト

テーマ : プログラミング
ジャンル : コンピュータ

コメントの投稿

非公開コメント

プロフィール

T GYOUTEN

Author:T GYOUTEN
F#と英単語とフリーソフトと読書に興味があります。
ホームページでフリーソフトも公開しています。どぞ御贔屓に。

最新記事
最新コメント
最新トラックバック
月別アーカイブ
カテゴリ
フリーエリア
フリーエリア
blogram投票ボタン
検索フォーム
RSSリンクの表示
リンク
ブロとも申請フォーム

この人とブロともになる

QRコード
QRコード
上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。