tagCANDY CGI VBレスキュー(花ちゃん) の Visual Basic 2010 用 掲示板(VB.NET 掲示板) [ツリー表示へ]   [Home]
一括表示(VB.NET VB2005)
タイトルDelgateの受け渡し?
記事No8806
投稿日: 2009/03/13(Fri) 10:12
投稿者ダンボ
お世話になっております。VB2005のTimerクラスをちょっと改良しようとして
下記コード(未完成)を作成中ですが、2箇所のAddressOf MyClass.EventProcで
コンパイルエラーが出ており解決策がわかりません。
エラーメッセージは、
「'AddressOf' オペランドはメソッドの名前でなければなりません。かっこは不要です。」

Public Class EventArgsSlideTimer
    Inherits System.EventArgs
    Public Profile As ProfileClass
    Public Sub New(ByVal Profile As ProfileClass)
        MyClass.Profile = Profile
    End Sub
End Class
Public Class SlideTimerClass
    Inherits System.Windows.Forms.Timer
    Private SlideProfile As ProfileClass
    Private EventProc As Predicate(Of EventHandler(Of EventArgsSlideTimer))
    Public Sub New(ByVal SlideProfile As ProfileClass, ByVal EventProc As Predicate(Of EventHandler(Of EventArgsSlideTimer)))
        MyClass.SlideProfile = SlideProfile
        MyClass.EventProc = EventProc
        AddHandler MyClass.Tick, AddressOf MyClass.EventProc
    End Sub
    Protected Overrides Sub Finalize()
        RemoveHandler MyClass.Tick, AddressOf MyClass.EventProc
        MyClass.Finalize()
    End Sub
End Class

[ツリー表示へ]
タイトルRe: Delgateの受け渡し?
記事No8807
投稿日: 2009/03/13(Fri) 13:29
投稿者魔界の仮面弁士
> VB2005のTimerクラスをちょっと改良しようとして
Timer クラスには 3 種類ありますが、今回使いたいのは、
System.Windows.Forms.Timer のクラスなのですね?


> 下記コード(未完成)を作成中ですが、
まずは、何をしたいのかを教えてください。
その未完成コードに何を求めているのかを知っているのは、ダンボさん自身だけです。

目的が分からないことには、このコードがあとちょっとで完成する段階なのか、
それとも、実装手法そのものから間違っているのかの判断も出来ません。


とりあえず、やりたいことを推測しながら答えると、こんなところでしょうか。


(1) Timer に ProfileClass を関連付けたい。
 → 手抜きでよければ、Timer の派生クラスを用意せずとも、
   Timer.Tag プロパティに放り込んでだけと言う手も使えます。

(2) SlideTimerClass 自身がタイマー処理を行いたい。
 → この場合、Tick イベントを使うべきではありません。
   かわりに、OnTick メソッドをオーバーロードするようにしましょう。

(3) SlideTimerClass の利用者が、タイマー処理を行いたい。
 → SlideTimerClass 内ではなく、利用者がイベントを捕らえてください。

(4) 利用者側でデリゲートを用意し、それを SlideTimerClass に処理させたい。
 → いろいろ間違ってます。以下参照。

まず、
> AddHandler MyClass.Tick, AddressOf MyClass.EventProc
の 第2引数に、何を引き渡すべきかを把握していますでしょうか。
ここにくるべきは、EventHandler 型のデリゲート インスタンスです。

もし、
> Private EventProc As Predicate(Of EventHandler(Of EventArgsSlideTimer))
をタイマーで処理したいのだとしたら、AddressOf を指定すべきではありません。

かといって、AddressOf を指定せずに、
  AddHandler MyClass.Tick, MyClass.EventProc
というのは、型が異なるので NG です。

何故なら、デリゲート「Predicate(Of EventHandler(Of EventArgsSlideTimer))」は、
 Function foo(ByVal e As EventHandler(Of EventArgsSlideTimer)) As Boolean
を要求しますが、本来指定すべき「EventHandler」の定義は、
 Sub foo(ByVal sender As Object, ByVal e As EventArgs)
であるからです。

AddressOf を使うなら、
 Public Sub New(…
  AddHandler MyClass.Tick, AddressOf foo
 End Sub
 Private Sub Foo(ByVal sender As Object, ByVal e As EventArgs)
  EventProc.Invoke(…
 End Sub
のような実装にする事はできるでしょう。もっとも、このようなコードは
お奨めできませんし、それが目的の処理かどうかも分かりませんけれども。

[ツリー表示へ]
タイトルRe^2: Delgateの受け渡し?
記事No8809
投稿日: 2009/03/13(Fri) 16:46
投稿者ダンボ
魔界の仮面弁士さん、いつも有難うございます。

> Timer クラスには 3 種類ありますが、今回使いたいのは、
> System.Windows.Forms.Timer のクラスなのですね?

それしか知りませんでした。急遽下記を眺めています。
http://www.atmarkit.co.jp/fdotnet/dotnettips/373threadtimer/threadtimer.html
http://www.atmarkit.co.jp/fdotnet/dotnettips/374timerstimer/timerstimer.html
http://www.atmarkit.co.jp/fdotnet/dotnettips/372formstimer/formstimer.html
System.Windows.Forms.Timerで十分と思います。

> (1) Timer に ProfileClass を関連付けたい。
そうです。最初は共通モジュールに
    Public Shared SlideTimer As Timer
    Public Shared SlideProfile As ProfileClass
でうまく制御できていました。ただスマートでないのでカプセル化したかっただけです。
Tagプロパティの活用で十分ですね。

> (2) SlideTimerClass 自身がタイマー処理を行いたい。
それは違います。あくまでも利用者クラス内のTick処理SubにTickイベントを
発生させるだけです。

> (3) SlideTimerClass の利用者が、タイマー処理を行いたい。
そうです。最初は利用者クラス内で、
        AddHandler SlideTimer.Tick, AddressOf Slide_Tick
        RemoveHandler SlideTimer.Tick, AddressOf Slide_Tick
を発行してうまく動作していました。

> (4) 利用者側でデリゲートを用意し、それを SlideTimerClass に処理させたい。
そうです。RemoveHandlerの発行箇所が複数あるので、それならばSlide_Tickアドレスを
SlideTimerClassに覚えさせて、
 NewまたはStartでAddHandler
 FinalizeまたはStopでRemoveHandler
できないかなぁ、と考えた次第です。

事情があってフォーム毎にtimerコントロールを貼り付けたくなく、システムで唯一の
タイマーを各フォームが排他で使うという基本方針でこんなになっています。
現状うまく動作しているのを、もう少しきれいなコンパクトなコードにできないかと
いう試みですので、(4)はあきらめてもよいです。

ただデリゲートの処理(呼ぶほうはともかく受ける方は)ってどうするのかなぁ
というのがここ1年くらいモヤモヤしているところです。

[ツリー表示へ]
タイトルRe^3: Delgateの受け渡し?
記事No8813
投稿日: 2009/03/14(Sat) 20:51
投稿者魔界の仮面弁士
> > (2) SlideTimerClass 自身がタイマー処理を行いたい。
> それは違います。あくまでも利用者クラス内のTick処理SubにTickイベントを
> 発生させるだけです。
う〜ん。そのことと、
Private EventProc As Predicate(Of EventHandler(Of EventArgsSlideTimer))
との関連性がわかりません。
Predicate(Of T) は、Booleanを返す「Function」であって、「Sub」では無いですよね。
Tick のためのデリゲートを渡したいなら、EventHandler 型になるはずですし。

Predicate(Of T) な Function 実装を、何のために使いたいのでしょうか?
呼び出すだけであれば、「Dim c As Boolean = Me.EventProc(obj)」だけであって、
クラス内で AddressOf を使う必要は無いはずですよ。


> > (4) 利用者側でデリゲートを用意し、それを SlideTimerClass に処理させたい。
> そうです。RemoveHandlerの発行箇所が複数あるので、それならばSlide_Tickアドレスを
> SlideTimerClassに覚えさせて、
>  NewまたはStartでAddHandler
>  FinalizeまたはStopでRemoveHandler
> できないかなぁ、と考えた次第です。

ファイナライザを使うと、ガベージコレクトによる回収が遅れます。
使わないで済む実装があるなら、使わない選択肢も模索してみてください。


また、元のコードについていうと、必ずしも Timer を継承させる必要は無く、
ヘルパ クラスを作るだけで良いような気もします。また、継承させるのであれば、
元の Timer が持っている、IContainer を受け取るコンストラクタを用意すべきかと。

コンポーネントが IContainer を受け取る場合、親フォームが破棄される際に
Dispose(True) によってタイマーも破棄されるようになりますが、今回の実装だと
それは行われませんよね。

[ツリー表示へ]
タイトルRe^4: Delegateの受け渡し?
記事No8816
投稿日: 2009/03/16(Mon) 10:36
投稿者ダンボ
魔界の仮面弁士さん、お手数掛けて済みません。

実装についてはもうTimer.Tabだけを活用した元のコードにして動作していますので
後は勉強だけのことです。

で、デリゲートのこともよくは分からず「関数を変数として扱う仕組み(汎関数)かな?」
程度で突撃していますのでご斟酌願います。

> > > (2) SlideTimerClass 自身がタイマー処理を行いたい。
> > それは違います。あくまでも利用者クラス内のTick処理SubにTickイベントを
> > 発生させるだけです。
> う〜ん。そのことと、
> Private EventProc As Predicate(Of EventHandler(Of EventArgsSlideTimer))
> との関連性がわかりません。

仕様が後出し後出しになって済みません。SlideTimerClassではTickイベントを
乗っ取って、EventArgs経由でProfileを返してやる、利用側クラスではそのProfile
を見て自分のリクエストしたTickでなければ何もしない。という構想でした。

EventProc はあくまでもAddHandlerとRemoveHandlerを、利用側クラスの延長として
定義側クラスの中に書けないかなという実験です。

[ツリー表示へ]