Excel VBA質問箱 IV

当質問箱は、有志のボランティア精神のおかげで成り立っています。
問題が解決したら、必ずお礼をしましょうね。
本サイトの基本方針をまとめました。こちら をご一読ください。

投稿種別の選択が必要です。ご注意ください。
迷惑投稿防止のため、URLの入力を制限しています。ご了承ください。


3113 / 13646 ツリー ←次へ | 前へ→

【64189】End With UO3 10/1/24(日) 12:34 質問[未読]
【64190】Re:End With kanabun 10/1/24(日) 14:11 発言[未読]
【64191】Re:End With UO3 10/1/24(日) 14:53 お礼[未読]
【64196】Re:End With YU-TANG 10/1/24(日) 21:41 発言[未読]
【64197】Re:End With ichinose 10/1/24(日) 22:08 発言[未読]
【64198】Re:End With UO3 10/1/24(日) 22:10 お礼[未読]
【64199】Re:End With ichinose 10/1/25(月) 7:59 発言[未読]
【64192】Re:End With ichinose 10/1/24(日) 14:58 発言[未読]
【64193】Re:End With UO3 10/1/24(日) 15:34 お礼[未読]

【64189】End With
質問  UO3  - 10/1/24(日) 12:34 -

引用なし
パスワード
   自分が書いてきたコードで気になったまま、まぁいいかと思っている
部分があります。以下は構文サンプルです。
(サンプルですので処理内容は無視してください)

途中でExit Sub で抜けた場合、End With は実行されません。
今まで障害は発生していないのでそのままにしていますが、
気にしなくてもいいものでしょうか?

Sub test()

 With Range("A1")
 
  If .Value = 1 Then
   MsgBox "Error"
   Exit Sub    '<== ここで抜けるとEnd With は実行されない。
  Else
   .Value = .Value + 1
  End If
 
 End With
 
End Sub

【64190】Re:End With
発言  kanabun  - 10/1/24(日) 14:11 -

引用なし
パスワード
   ▼UO3 さん:
こんにちは〜

>
>途中でExit Sub で抜けた場合、End With は実行されません。

ちなみに、こういう構文はどう考えるのでしょう?

Option Explicit

Sub Test2()
 Exit Sub '<== ここで抜けるとEnd Sub は実行されない?
End Sub

Sub Test3()
  Dim data

  If IsEmpty(data) Then'<- End If は実行されない?
    Exit Sub
  End If

End Sub

【64191】Re:End With
お礼  UO3  - 10/1/24(日) 14:53 -

引用なし
パスワード
   ▼kanabun さん:

いつもいつも、ご指導ありがとうございます。
非常にわかりやすい例でアドバイスいただき深謝です。

Exitで抜けるタイミングでEnd Withが処理している
【参照の解放】がなされるから気にする話ではないということですね。

【64192】Re:End With
発言  ichinose  - 10/1/24(日) 14:58 -

引用なし
パスワード
   ▼UO3 さん:
こんにちは。



With をアドレッシングだと考えると

クラスモジュール(クラス名Class1)に

Option Explicit
Private Sub Class_Initialize()
  Debug.Print "インスタンス 作成"
End Sub
Private Sub Class_Terminate()
  Debug.Print "インスタンス 消滅"
End Sub


として、

標準モジュールに

'=======================================
Sub test1()
  With New Class1
  MsgBox "Break 1"
  End With
  MsgBox "Break 2"
End Sub

これを実行すると、Break1では、インスタンスが作成され
(作成された証拠に イミディエイトに「インスタンス 作成」が表示)、
Break2では、解放(イミディエイトに「インスタンス 消滅」が表示)されています。


Sub test2()
  With New Class1
  MsgBox "Break 1"
  Exit Sub
  End With
  MsgBox "break 2"
End Sub

このtest2でも 「インスタンス 消滅」が表示されますよね!!
よって、プロシジャー終了時にアドレッシングの解除はされていますね。

が、私の意見としては、原則プロシジャー内の出口は一つでよい
という考え方です(構造化プログラミングでは良く見かける記述です)。
こういう疑問が沸かないように

Sub test()

 With Range("A1")
 
  If .Value = 1 Then
   MsgBox "Error"
  'Exit Sub  '←削除
  Else
   .Value = .Value + 1
  End If
 
 End With
 
End Sub


とするべきだと思いますけどねえ

【64193】Re:End With
お礼  UO3  - 10/1/24(日) 15:34 -

引用なし
パスワード
   ▼ichinose さん:

本当に消滅していることを実証していただき気持が
スカッとさわやか!という感じです。
ありがとうございます。

>私の意見としては、原則プロシジャー内の出口は一つでよい

そのとおりだと思います。ロジックの流れが、しっかりとすると
いうか、将来、コードを追加した場合に、途中でぬけているところを
うっかり見過ごし、デバッグに時間がかかるリスクも軽減されますしね。

できるだけ、心がけていきたいと思います。
(といいながら、つい、手軽にすませて途中で抜けてしまうコードを
 これからも書いてしまうかもしれませんが)

【64196】Re:End With
発言  YU-TANG  - 10/1/24(日) 21:41 -

引用なし
パスワード
   こんばんは、YU-TANG です。

細かいことですが、もしかするとその細かいことを気にされている
かもしれないので、念のため。

▼UO3 さん:
> Exitで抜けるタイミングでEnd Withが処理している
> 【参照の解放】がなされるから気にする話ではないということですね。

厳密に言うと、End With が行っているのは単にオブジェクトの修飾補完を
終了するだけです。
それに伴って参照が解放される場合もありますが、されない場合も
あります。なので、End With を通ったからといって、参照の解放を
当てにしない(期待しない)方が無難です。

たとえば、ichinose さんのお書きになった【64192】のサンプルを
お借りするとして。

Sub test2()
  With New Scripting.Dictionary    ' 事前バインディング(Scripting.Runtime ライブラリに参照設定)
    .Add 1, GetClass1
    Debug.Print "Break 1"
  End With
  Debug.Print "Break 2"
End Sub

Sub test3()
  With CreateObject("Scripting.Dictionary")    ' 実行時バインディング(参照設定不要)
    .Add 1, GetClass1
    Debug.Print "Break 1"
  End With
  Debug.Print "Break 2"
End Sub

Function GetClass1() As Class1
  Set GetClass1 = New Class1
End Function

test2 と test3 を実行してイミディエイト ウィンドウを確認されると、
なかなか興味深い出力結果が得られると思います。

それでは。

【64197】Re:End With
発言  ichinose  - 10/1/24(日) 22:08 -

引用なし
パスワード
   YU-TANG さん
こんばんは。

>厳密に言うと、End With が行っているのは単にオブジェクトの修飾補完を
>終了するだけです。
>それに伴って参照が解放される場合もありますが、されない場合も
>あります。なので、End With を通ったからといって、参照の解放を
>当てにしない(期待しない)方が無難です。
これは、初めて知りました、ありがとうございます。
本当ですね!!開放されない場合もあるんですね!!
内部的に参照が残っているのでしょうかねえ??


だとすると・・・、意図的に開放したいなら

Sub test4()
  Dim dic As Object
  Set dic = CreateObject("Scripting.Dictionary")
  dic.Add 1, GetClass1
  Debug.Print "Break 1"
  Set dic = Nothing
  Debug.Print "Break 2"
End Sub

と明確に記述すべきなのかなあ

【64198】Re:End With
お礼  UO3  - 10/1/24(日) 22:10 -

引用なし
パスワード
   ▼YU-TANG さん:

 はじめまして!
 (他の方々のトピでは、YU-TANGさんの回答、いろいろ拝見し、
  勉強させていただいてますが)
 興味深いアドバイスありがとうございます。
 あす、会社で(仕事をそっちのけにして)頂戴したサンプルで
 勉強をしてみます。

 当方、VBAといいましても、ほんの表面でウロウロ、スタッフが
 まちまちに事務処理を行うのを、統一した手順で実行させるために
 見よう見まねで作成しているレベルでして、YU-TANGさん、kanabunさん
 ichinoseさんといったスーパースターにアドバイスいただけるだけで
 光栄に思っております。

 いずれ、近く、社会人生活を卒業しましたら基礎からじっくり勉強して
 みたいなと、そう思っております。
 

【64199】Re:End With
発言  ichinose  - 10/1/25(月) 7:59 -

引用なし
パスワード
   おはようございます。

End Withでオブジェクトが開放されない

これをループさせるとどうなるのだろう。

Sub test3()
  Dim i As Long
  Do Until i = 5
    Debug.Print "b1"
    With CreateObject("Scripting.Dictionary")
     .Add 1, GetClass1
    End With
    Debug.Print "b2"
    i = i + 1
  Loop
End Sub

と思いやってみると・・・、
2回目以降の

With CreateObject("Scripting.Dictionary")

で参照しているオブジェクトを開放し、新たにインスタンスを作成している
ように見えます。

なんとなく、きちんとした仕様のように見えます。

では、この現象(End Withでオブジェクトを開放する場合としない場合が存在する)
の理由は? 何故? という疑問が残りますねえ!!
インスタンス作成時の処理速度に関係があるのでしょうかねえ!!

これも CreateObjectを使えば、End Withで開放されない

が間違いないと仮定してですが・・・。

3113 / 13646 ツリー ←次へ | 前へ→
ページ:  ┃  記事番号:
2610219
(SS)C-BOARD v3.8 is Free