| こちらで実験すると、再現するどころかエラーになってしまったので、 ちょっと悩んでいたのですが、投稿いただいた質問コードは 実際のコードと同一というわけではなかったのですね。
■No88576 (パヨンパヨン さん) に返信 > としてあるのがエラーの原因で、 > frm.BeginInvoke(Sub() SetText(Me.TextBox3, i)) > とするとうまくいきました。
いずれにせよ、マルチスレッドを意識したコードにするのなら、 フォームの「既定のインスタンス」を使わないコーディングに慣れておいた方が良いですよ。
>>【問題点1】ラムダ式の遅延評価と変数のスコープ > ラムダ式のことは理解しています。 一番最初の質問である 「最後に代入された値しか表示されません。」 の要因かとも思ったので、一応指摘させていただきました。
>>【問題点2】既定のフォームインスタンス Form1 と明示的インスタンス frm >>Form1.TextBox3 を扱うために、何故 frm の BeginInvoke を呼び出しているのでしょうか。 > これはフォーム上に全てのコードを書いてしまうと長くなって読みづらいので
Form に書くべき処理は、本来はそのフォーム自身のふるまいだけなので、 ビジネスロジック等は、別の Class や Module に分けたりしますね。
それでも Form のコードが多くなってしまう場合には、 Partial で分割するという方法もあるようです。
> 普段は、別のモジュール上にコードを書いているためです。 > 他のコードをコピーして流用したため、残ってしまいました。
frm が Shared な変数あるいは Module 上の変数だとすると、 同一フォームの複数インスタンスが生成されていた場合には 都合が悪いかも知れません。
>> ''方法3 > 'Invoke(New MethodInvoker( > ' Sub() ちなみにこれは、 Invoke(New Action(Sub() や Invoke(Sub() でも OK です。いずれも同じ意味になります。
※上記は MyBase.Invoke の意味なので、Module 等に記述する場合には 対象コントロールの Invoke メソッドの呼び出しに変更する必要があります。
> '方法2 > 'Invoke(Sub() 複数の引数(x, y, z)) > がもっともコードが短く単純なので、ベストチョイスのように思えますが、
先の例の場合、「Private Sub 複数の引数(…)」を用意していましたよね。
クラスやモジュールに、再利用性の無い(かつ、比較的短い処理の)メソッドが 多数存在してしまうことを嫌うような場合においては、方法3 のように、 ラムダ式やローカル関数で済ませる場合もあるということです。
ちなみにローカル関数は VB には無い機能です。(C#7.0 以降)
> という三つの方法をご提示くださりましたが、 > これらはどれを使っても計算速度やPC負荷などに全く違いは見られないと考えて良いのでしょうか? 厳密にいえば、まったく同じコンパイル結果になるわけではありません。 パフォーマンス差については、各種条件によってかわってくるものなので、 ご自身で実際に検証頂いた上でご判断ください。
ただ、手順や仕組みはどうあれ、同じ結果を得られるのであれば、 その時々で使いやすいものを選んでいけば良いのではないでしょうか。
で。直接的な速度差はさておき、コンパイル結果がもっとも単純となるのは方法1 です。
>> '方法1 >> Invoke(New Action(Of String, String, Color)(AddressOf 複数の引数), x, y, z) これは匿名型等は必要とせず、元のコードのとおりに、 Dim act As Action(Of String, String, Color) = AddressOf Me.複数の引数 MyBase.Invoke(act, New Object() { x, y, z }) のような形にコンパイルされるだけで済みます。 (実際には act という変数が作られるわけではないですが、説明のために付加しています)
しかし方法2 や 3 の場合は、局所変数である x/y/z の 3 つ(それと、Me を含めた 4 つ)の値を フィールド変数として閉包した匿名クロージャと、匿名デリゲートが作成されることになります。
たとえば >> '方法2 >> Invoke(Sub() 複数の引数(x, y, z)) というコードのコンパイル結果は、Visual Basic 的な文法イメージでいうと Dim closure As New 匿名型() With { .[Self] = Me, .[x] = x, .[y] = y, .[z] = z } Dim act As 匿名デリゲート = AddressOf closure.Lamda MyBase.Invoke(act, New Object() { x, y, z }) のようになるため、手順的には方法 1 よりも一手間増えます。
また、これの呼び出しのために Partial Class Form1 Friend Delegate Sub 匿名デリゲート() Friend Class 匿名型 Public [Self] As Form1 Public [x] As String Public [y] As String Public [z] As Color Friend Sub Lamda() Me.[Self].複数の引数(Me.[x], Me.[y], Me.[z]) End Sub End Class End Class に相当する物が内部的に作られることにもなりますね。 |